From 2b906615c608d17eb6529f7455e08990e619890d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 27 Oct 2019 09:37:57 +0100 Subject: [PATCH 01/57] Create a higher level of abastraction for hierarchical sources --- NBi.Core/Hierarchical/AbstractPathEngine.cs | 26 +++++++++++++++++++ NBi.Core/Hierarchical/AbstractSelect.cs | 16 ++++++++++++ NBi.Core/Hierarchical/AttributeSelect.cs | 17 ++++++++++++ .../{Xml => Hierarchical}/ElementSelect.cs | 8 +++--- .../{Xml => Hierarchical}/EvaluateSelect.cs | 8 +++--- .../Hierarchical/HierarchicalSelectFactory.cs | 21 +++++++++++++++ .../{ => Hierarchical}/Xml/XPathEngine.cs | 23 ++++++---------- .../{ => Hierarchical}/Xml/XPathFileEngine.cs | 10 +++---- .../{ => Hierarchical}/Xml/XPathUrlEngine.cs | 6 ++--- .../Xml/XmlIgnoreNamespaceReader.cs | 2 +- .../Xml/XmlWrappingReader.cs | 2 +- NBi.Core/NBi.Core.csproj | 21 ++++++++------- .../Resolver/ResultSetResolverFactory.cs | 2 +- .../Resolver/XPathResultSetResolver.cs | 2 +- .../Resolver/XPathResultSetResolverArgs.cs | 2 +- NBi.Core/ResultSet/ResultSetServiceBuilder.cs | 2 +- .../Scalar/Resolver/ScalarResolverFactory.cs | 2 +- NBi.Core/Xml/AbstractSelect.cs | 18 ------------- NBi.Core/Xml/AttributeSelect.cs | 19 -------------- NBi.Core/Xml/SelectFactory.cs | 22 ---------------- .../Helper/ResultSetResolverArgsBuilder.cs | 5 ++-- .../Helper/SequenceResolverArgsBuilder.cs | 2 +- NBi.NUnit/Builder/ResultSetEqualToBuilder.cs | 2 +- NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs | 2 +- NBi.NUnit/Builder/ScalarScoreBuilder.cs | 2 +- .../BaseResultSetComparisonConstraint.cs | 2 +- NBi.NUnit/Scoring/ScoreConstraint.cs | 2 +- .../Xml/Resources/PurchaseOrders.xml | 0 .../PurchaseOrdersDefaultNamespace.xml | 0 .../PurchaseOrdersManyNamespaces.xml | 0 .../{ => Hierarchical}/Xml/XPathEngineTest.cs | 9 +++---- NBi.Testing.Core/NBi.Testing.Core.csproj | 8 +++--- 32 files changed, 134 insertions(+), 129 deletions(-) create mode 100644 NBi.Core/Hierarchical/AbstractPathEngine.cs create mode 100644 NBi.Core/Hierarchical/AbstractSelect.cs create mode 100644 NBi.Core/Hierarchical/AttributeSelect.cs rename NBi.Core/{Xml => Hierarchical}/ElementSelect.cs (61%) rename NBi.Core/{Xml => Hierarchical}/EvaluateSelect.cs (61%) create mode 100644 NBi.Core/Hierarchical/HierarchicalSelectFactory.cs rename NBi.Core/{ => Hierarchical}/Xml/XPathEngine.cs (80%) rename NBi.Core/{ => Hierarchical}/Xml/XPathFileEngine.cs (93%) rename NBi.Core/{ => Hierarchical}/Xml/XPathUrlEngine.cs (89%) rename NBi.Core/{ => Hierarchical}/Xml/XmlIgnoreNamespaceReader.cs (92%) rename NBi.Core/{ => Hierarchical}/Xml/XmlWrappingReader.cs (99%) delete mode 100644 NBi.Core/Xml/AbstractSelect.cs delete mode 100644 NBi.Core/Xml/AttributeSelect.cs delete mode 100644 NBi.Core/Xml/SelectFactory.cs rename NBi.Testing.Core/{ => Hierarchical}/Xml/Resources/PurchaseOrders.xml (100%) rename NBi.Testing.Core/{ => Hierarchical}/Xml/Resources/PurchaseOrdersDefaultNamespace.xml (100%) rename NBi.Testing.Core/{ => Hierarchical}/Xml/Resources/PurchaseOrdersManyNamespaces.xml (100%) rename NBi.Testing.Core/{ => Hierarchical}/Xml/XPathEngineTest.cs (98%) diff --git a/NBi.Core/Hierarchical/AbstractPathEngine.cs b/NBi.Core/Hierarchical/AbstractPathEngine.cs new file mode 100644 index 000000000..44a22260d --- /dev/null +++ b/NBi.Core/Hierarchical/AbstractPathEngine.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using NBi.Core.Hierarchical; +using NBi.Core.ResultSet; + +namespace NBi.Core.Hierarchical.Xml +{ + public abstract class AbstractPathEngine + { + protected IEnumerable Selects { get; } + protected string From { get; } + + public AbstractPathEngine(string from, IEnumerable selects) + => (From, Selects) = (from, selects); + + public abstract IEnumerable Execute(); + } +} diff --git a/NBi.Core/Hierarchical/AbstractSelect.cs b/NBi.Core/Hierarchical/AbstractSelect.cs new file mode 100644 index 000000000..f31366f06 --- /dev/null +++ b/NBi.Core/Hierarchical/AbstractSelect.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Hierarchical +{ + public class AbstractSelect + { + public string Path { get; } + + protected AbstractSelect(string path) + => Path = path; + } +} diff --git a/NBi.Core/Hierarchical/AttributeSelect.cs b/NBi.Core/Hierarchical/AttributeSelect.cs new file mode 100644 index 000000000..b7d1590e2 --- /dev/null +++ b/NBi.Core/Hierarchical/AttributeSelect.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Hierarchical +{ + public class AttributeSelect: ElementSelect + { + public string Attribute { get; } + + internal AttributeSelect(string path, string attribute) + : base(path) + => Attribute = attribute; + } +} diff --git a/NBi.Core/Xml/ElementSelect.cs b/NBi.Core/Hierarchical/ElementSelect.cs similarity index 61% rename from NBi.Core/Xml/ElementSelect.cs rename to NBi.Core/Hierarchical/ElementSelect.cs index 83d171642..9aa03ec51 100644 --- a/NBi.Core/Xml/ElementSelect.cs +++ b/NBi.Core/Hierarchical/ElementSelect.cs @@ -4,13 +4,11 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical { public class ElementSelect : AbstractSelect { - internal ElementSelect(string xpath) - : base(xpath) - { - } + internal ElementSelect(string path) + : base(path) { } } } diff --git a/NBi.Core/Xml/EvaluateSelect.cs b/NBi.Core/Hierarchical/EvaluateSelect.cs similarity index 61% rename from NBi.Core/Xml/EvaluateSelect.cs rename to NBi.Core/Hierarchical/EvaluateSelect.cs index dcd705653..6dc288124 100644 --- a/NBi.Core/Xml/EvaluateSelect.cs +++ b/NBi.Core/Hierarchical/EvaluateSelect.cs @@ -4,13 +4,11 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical { public class EvaluateSelect: ElementSelect { - internal EvaluateSelect(string xpath) - : base(xpath) - { - } + internal EvaluateSelect(string path) + : base(path) { } } } diff --git a/NBi.Core/Hierarchical/HierarchicalSelectFactory.cs b/NBi.Core/Hierarchical/HierarchicalSelectFactory.cs new file mode 100644 index 000000000..1603c010b --- /dev/null +++ b/NBi.Core/Hierarchical/HierarchicalSelectFactory.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Hierarchical +{ + public class HierarchicalSelectFactory + { + public AbstractSelect Instantiate(string path, string attribute, bool isEvaluate) + { + if (isEvaluate) + return new EvaluateSelect(path); + if (string.IsNullOrEmpty(attribute)) + return new ElementSelect(path); + else + return new AttributeSelect(path, attribute); + } + } +} diff --git a/NBi.Core/Xml/XPathEngine.cs b/NBi.Core/Hierarchical/Xml/XPathEngine.cs similarity index 80% rename from NBi.Core/Xml/XPathEngine.cs rename to NBi.Core/Hierarchical/Xml/XPathEngine.cs index 32fb1d9f0..7095f74e6 100644 --- a/NBi.Core/Xml/XPathEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathEngine.cs @@ -8,26 +8,19 @@ using System.Xml; using System.Xml.Linq; using System.Xml.XPath; +using NBi.Core.Hierarchical; using NBi.Core.ResultSet; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical.Xml { - public abstract class XPathEngine + public abstract class XPathEngine : AbstractPathEngine { - private readonly IEnumerable selects; - private readonly string from; public string DefaultNamespacePrefix { get; } public bool IsIgnoreNamespace { get; } - public XPathEngine(string from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) - { - this.from = from; - this.selects = selects; - DefaultNamespacePrefix = defaultNamespacePrefix; - IsIgnoreNamespace = isIgnoreNamespace; - } - - public abstract IEnumerable Execute(); + protected XPathEngine(string from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) + : base(from, selects) + => (DefaultNamespacePrefix, IsIgnoreNamespace) = (defaultNamespacePrefix, isIgnoreNamespace); public IEnumerable Execute(XDocument items) { @@ -40,7 +33,7 @@ public IEnumerable Execute(XDocument items) if (namespaceNode.Name.LocalName != "xmlns") nsMgr.AddNamespace(namespaceNode.Name.LocalName, namespaceNode.Value); - var result = from item in items.XPathSelectElements(@from, nsMgr) + var result = from item in items.XPathSelectElements(From, nsMgr) select GetObj(item, nsMgr); return result; @@ -49,7 +42,7 @@ public IEnumerable Execute(XDocument items) private object GetObj(XElement x, IXmlNamespaceResolver ns) { var obj = new List(); - obj.AddRange(BuildXPaths(x, ns, selects).ToArray()); + obj.AddRange(BuildXPaths(x, ns, Selects).ToArray()); return obj; } diff --git a/NBi.Core/Xml/XPathFileEngine.cs b/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs similarity index 93% rename from NBi.Core/Xml/XPathFileEngine.cs rename to NBi.Core/Hierarchical/Xml/XPathFileEngine.cs index 3e833fe08..3a30d51a2 100644 --- a/NBi.Core/Xml/XPathFileEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs @@ -9,20 +9,16 @@ using System.Xml; using System.Xml.Linq; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical.Xml { public class XPathFileEngine : XPathEngine { public string BasePath { get; } public IScalarResolver ResolverPath { get; } - - + public XPathFileEngine(IScalarResolver resolverPath, string basePath, string from, IEnumerable selects, string defaultNamespacePrefix, bool isRemoveDefaultNamespace) : base(from, selects, defaultNamespacePrefix, isRemoveDefaultNamespace) - { - BasePath = basePath; - ResolverPath = resolverPath; - } + => (BasePath, ResolverPath) = (basePath, resolverPath); public override IEnumerable Execute() { diff --git a/NBi.Core/Xml/XPathUrlEngine.cs b/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs similarity index 89% rename from NBi.Core/Xml/XPathUrlEngine.cs rename to NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs index d233ed56c..3db3a97c3 100644 --- a/NBi.Core/Xml/XPathUrlEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using System.Xml.Linq; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical.Xml { public class XPathUrlEngine : XPathEngine { @@ -15,9 +15,7 @@ public class XPathUrlEngine : XPathEngine public XPathUrlEngine(string url, string from, IEnumerable selects, string defaultNamespacePrefix) : base(from, selects, defaultNamespacePrefix, false) - { - this.Url = url; - } + => Url = url; public override IEnumerable Execute() { diff --git a/NBi.Core/Xml/XmlIgnoreNamespaceReader.cs b/NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs similarity index 92% rename from NBi.Core/Xml/XmlIgnoreNamespaceReader.cs rename to NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs index 0b3372b4c..80b80ec7f 100644 --- a/NBi.Core/Xml/XmlIgnoreNamespaceReader.cs +++ b/NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Xml; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical.Xml { class XmlIgnoreNamespaceReader : XmlWrappingReader { diff --git a/NBi.Core/Xml/XmlWrappingReader.cs b/NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs similarity index 99% rename from NBi.Core/Xml/XmlWrappingReader.cs rename to NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs index 92e92218a..0c83dc0ac 100644 --- a/NBi.Core/Xml/XmlWrappingReader.cs +++ b/NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs @@ -6,7 +6,7 @@ using System.Xml; using System.Xml.Schema; -namespace NBi.Core.Xml +namespace NBi.Core.Hierarchical.Xml { class XmlWrappingReader : XmlReader, IXmlLineInfo { diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 6cf0776fb..3a60ff119 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -248,6 +248,7 @@ + @@ -835,16 +836,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs index 12145953a..da1449aa9 100644 --- a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs +++ b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs @@ -3,7 +3,7 @@ using System.Data; using System.Linq; using NBi.Core.Query; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Query.Resolver; using NBi.Core.Injection; using NBi.Core.FlatFile; diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs index 0f7551a84..3b9086826 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs +++ b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs @@ -1,5 +1,5 @@ using NBi.Core.Query; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using System; using System.Collections.Generic; using System.Data; diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs index 82df4bd2a..dd748ee13 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs +++ b/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs @@ -1,5 +1,5 @@ using NBi.Core.Query; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using System; using System.Collections.Generic; using System.Data; diff --git a/NBi.Core/ResultSet/ResultSetServiceBuilder.cs b/NBi.Core/ResultSet/ResultSetServiceBuilder.cs index 5c5aaa914..917ed4b92 100644 --- a/NBi.Core/ResultSet/ResultSetServiceBuilder.cs +++ b/NBi.Core/ResultSet/ResultSetServiceBuilder.cs @@ -3,7 +3,7 @@ using System.Data; using System.Linq; using NBi.Core.Query; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.ResultSet.Resolver; using NBi.Core.Transformation; using NBi.Core.ResultSet.Alteration; diff --git a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs index 742e52967..b109beb41 100644 --- a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs +++ b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs @@ -3,7 +3,7 @@ using System.Data; using System.Linq; using NBi.Core.Query; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Query.Resolver; using NBi.Core.Injection; using System.Reflection; diff --git a/NBi.Core/Xml/AbstractSelect.cs b/NBi.Core/Xml/AbstractSelect.cs deleted file mode 100644 index 61f945786..000000000 --- a/NBi.Core/Xml/AbstractSelect.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Xml -{ - public class AbstractSelect - { - protected AbstractSelect(string xpath) - { - this.Path = xpath; - } - - public string Path { get; private set; } - } -} diff --git a/NBi.Core/Xml/AttributeSelect.cs b/NBi.Core/Xml/AttributeSelect.cs deleted file mode 100644 index fba3200fe..000000000 --- a/NBi.Core/Xml/AttributeSelect.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Xml -{ - public class AttributeSelect: ElementSelect - { - internal AttributeSelect(string xpath, string attribute) - : base(xpath) - { - this.Attribute = attribute; - } - - public string Attribute { get; private set; } - } -} diff --git a/NBi.Core/Xml/SelectFactory.cs b/NBi.Core/Xml/SelectFactory.cs deleted file mode 100644 index 57ebdb64f..000000000 --- a/NBi.Core/Xml/SelectFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Xml -{ - public class SelectFactory - { - public AbstractSelect Instantiate(string xpath, string attribute, bool isEvaluate) - { - if (isEvaluate) - return new EvaluateSelect(xpath); - if (String.IsNullOrEmpty(attribute)) - return new ElementSelect(xpath); - else - return new AttributeSelect(xpath, attribute); - - } - } -} diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 9fbd66e52..198567be0 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -3,7 +3,8 @@ using NBi.Core.ResultSet.Resolver; using NBi.Core.Sequence.Resolver; using NBi.Core.Variable; -using NBi.Core.Xml; +using NBi.Core.Hierarchical; +using NBi.Core.Hierarchical.Xml; using NBi.Xml.Items; using NBi.Xml.Items.ResultSet; using NBi.Xml.Items.ResultSet.Combination; @@ -183,7 +184,7 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceVerbose, "ResultSet defined through an xml-source."); var selects = new List(); - var selectFactory = new SelectFactory(); + var selectFactory = new HierarchicalSelectFactory(); foreach (var select in xmlSource.XPath.Selects) selects.Add(selectFactory.Instantiate(select.Value, select.Attribute, select.Evaluate)); diff --git a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs index bf9cf25ea..8422d2beb 100644 --- a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs @@ -10,7 +10,7 @@ using NBi.Core.Sequence.Resolver; using NBi.Core.Sequence.Resolver.Loop; using NBi.Core.Variable; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Xml.Items; using NBi.Xml.Items.ResultSet; using NBi.Xml.Items.Xml; diff --git a/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs b/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs index 80f201f32..7ee694154 100644 --- a/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs @@ -10,7 +10,7 @@ using NBi.Xml.Constraints; using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; using System.Data; using NBi.Core.ResultSet.Resolver; diff --git a/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs b/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs index a240fe4e2..3077f9272 100644 --- a/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs @@ -9,7 +9,7 @@ using NBi.Xml.Constraints; using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; using NBi.NUnit.ResultSetComparison; using System.Data; diff --git a/NBi.NUnit/Builder/ScalarScoreBuilder.cs b/NBi.NUnit/Builder/ScalarScoreBuilder.cs index 5a1d148da..c79998b4b 100644 --- a/NBi.NUnit/Builder/ScalarScoreBuilder.cs +++ b/NBi.NUnit/Builder/ScalarScoreBuilder.cs @@ -10,7 +10,7 @@ using NBi.Xml.Constraints; using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; using System.Data; using NBi.Core.ResultSet.Resolver; diff --git a/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs b/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs index 8f4490d0e..1ce31c0b3 100644 --- a/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs +++ b/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs @@ -8,7 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework.FailureMessage; using NBi.Framework; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; using NBi.Core.ResultSet.Analyzer; using NBi.Core.ResultSet.Resolver; diff --git a/NBi.NUnit/Scoring/ScoreConstraint.cs b/NBi.NUnit/Scoring/ScoreConstraint.cs index 1fd9d2a3a..9f798f53b 100644 --- a/NBi.NUnit/Scoring/ScoreConstraint.cs +++ b/NBi.NUnit/Scoring/ScoreConstraint.cs @@ -8,7 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework.FailureMessage; using NBi.Framework; -using NBi.Core.Xml; +using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; using NBi.Core.ResultSet.Analyzer; using NBi.Core.ResultSet.Resolver; diff --git a/NBi.Testing.Core/Xml/Resources/PurchaseOrders.xml b/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrders.xml similarity index 100% rename from NBi.Testing.Core/Xml/Resources/PurchaseOrders.xml rename to NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrders.xml diff --git a/NBi.Testing.Core/Xml/Resources/PurchaseOrdersDefaultNamespace.xml b/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersDefaultNamespace.xml similarity index 100% rename from NBi.Testing.Core/Xml/Resources/PurchaseOrdersDefaultNamespace.xml rename to NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersDefaultNamespace.xml diff --git a/NBi.Testing.Core/Xml/Resources/PurchaseOrdersManyNamespaces.xml b/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersManyNamespaces.xml similarity index 100% rename from NBi.Testing.Core/Xml/Resources/PurchaseOrdersManyNamespaces.xml rename to NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersManyNamespaces.xml diff --git a/NBi.Testing.Core/Xml/XPathEngineTest.cs b/NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs similarity index 98% rename from NBi.Testing.Core/Xml/XPathEngineTest.cs rename to NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs index 9ff5a2f5d..64d60e112 100644 --- a/NBi.Testing.Core/Xml/XPathEngineTest.cs +++ b/NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs @@ -1,5 +1,6 @@ -using NBi.Core.Scalar.Resolver; -using NBi.Core.Xml; +using NBi.Core.Hierarchical; +using NBi.Core.Hierarchical.Xml; +using NBi.Core.Scalar.Resolver; using NUnit.Framework; using System; using System.Collections.Generic; @@ -10,7 +11,7 @@ using System.Threading.Tasks; using System.Xml.Linq; -namespace NBi.Testing.Core.Xml +namespace NBi.Testing.Core.Hierarchical.Xml { public class XPathStreamEngineTest { @@ -91,8 +92,6 @@ public void Execute_Example_RowCount(string from, int rowCount) var result = engine.Execute(); Assert.That(result.Count, Is.EqualTo(rowCount)); } - - } [Test] diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 74fae84ea..eecbae273 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -259,7 +259,7 @@ - + @@ -296,7 +296,7 @@ - + @@ -317,10 +317,10 @@ - + - + From 0ef0415c98a073f2bca78b3a80c05130e4d0484f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 27 Oct 2019 13:08:40 +0100 Subject: [PATCH 02/57] Add Json implemntation of the engine --- NBi.Core/Hierarchical/AbstractPathEngine.cs | 2 +- NBi.Core/Hierarchical/Json/JsonPathEngine.cs | 66 ++++++ .../Hierarchical/Json/JsonPathFileEngine.cs | 45 ++++ NBi.Core/NBi.Core.csproj | 2 + .../Hierarchical/Json/JsonPathEngineTest.cs | 202 ++++++++++++++++++ .../Json/Resources/PurchaseOrders.json | 146 +++++++++++++ NBi.Testing.Core/NBi.Testing.Core.csproj | 4 + 7 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 NBi.Core/Hierarchical/Json/JsonPathEngine.cs create mode 100644 NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs create mode 100644 NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs create mode 100644 NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json diff --git a/NBi.Core/Hierarchical/AbstractPathEngine.cs b/NBi.Core/Hierarchical/AbstractPathEngine.cs index 44a22260d..37746c447 100644 --- a/NBi.Core/Hierarchical/AbstractPathEngine.cs +++ b/NBi.Core/Hierarchical/AbstractPathEngine.cs @@ -11,7 +11,7 @@ using NBi.Core.Hierarchical; using NBi.Core.ResultSet; -namespace NBi.Core.Hierarchical.Xml +namespace NBi.Core.Hierarchical { public abstract class AbstractPathEngine { diff --git a/NBi.Core/Hierarchical/Json/JsonPathEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathEngine.cs new file mode 100644 index 000000000..63e3eb4ae --- /dev/null +++ b/NBi.Core/Hierarchical/Json/JsonPathEngine.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NBi.Core.Hierarchical; +using NBi.Core.Hierarchical.Xml; +using NBi.Core.ResultSet; +using System.Text.RegularExpressions; + +namespace NBi.Core.Hierarchical.Json +{ + public abstract class JsonPathEngine : AbstractPathEngine + { + protected JsonPathEngine(string from, IEnumerable selects) + : base(from, selects) { } + + public IEnumerable Execute(JToken items) + { + var result = from item in items.SelectTokens(From) + select GetObj(item); + + return result; + } + + private object GetObj(JToken item) + { + var obj = new List(); + obj.AddRange(BuildPaths(item, Selects).ToArray()); + return obj; + } + + protected internal IEnumerable BuildPaths(JToken item, IEnumerable selects) + { + foreach (var select in selects) + { + var path = select.Path.Trim(); + var root = item; + if (path.StartsWith("!")) + { + var match = Regex.Matches(path, @"^(!*)").Cast().First(); + var i = 0; + while (i < match.Value.Length && !string.IsNullOrEmpty(root.Path)) + { + var previousParentPath = root.Path; + root = root.Parent; + if (previousParentPath != root.Path) + i++; + } + + path = $"${ path.Substring(match.Value.Length)}"; + } + + yield return + ( + root.SelectToken(path) + ?? new JValue("(null)") + ).ToObject(); + } + } + } +} diff --git a/NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs new file mode 100644 index 000000000..4ecedc5f0 --- /dev/null +++ b/NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs @@ -0,0 +1,45 @@ +using NBi.Core.Scalar.Resolver; +using NBi.Extensibility; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace NBi.Core.Hierarchical.Json +{ + public class JsonPathFileEngine : JsonPathEngine + { + public string BasePath { get; } + public IScalarResolver ResolverPath { get; } + + public JsonPathFileEngine(IScalarResolver resolverPath, string basePath, string from, IEnumerable selects) + : base(from, selects) + => (BasePath, ResolverPath) = (basePath, resolverPath); + + public override IEnumerable Execute() + { + var filePath = EnsureFileExist(); + + using (var textReader = GetTextReader(filePath)) + { + var json = JToken.ReadFrom(new JsonTextReader(textReader)); + return Execute(json); + } + } + + protected virtual string EnsureFileExist() + { + var filePath = PathExtensions.CombineOrRoot(BasePath, string.Empty, ResolverPath.Execute()); + if (!File.Exists(filePath)) + throw new ExternalDependencyNotFoundException(filePath); + return filePath; + } + + protected virtual TextReader GetTextReader(string filePath) + => new StreamReader(filePath); + } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 3a60ff119..74910c537 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -249,6 +249,8 @@ + + diff --git a/NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs b/NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs new file mode 100644 index 000000000..f8a05378a --- /dev/null +++ b/NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs @@ -0,0 +1,202 @@ +using NBi.Core.Hierarchical; +using NBi.Core.Hierarchical.Json; +using NBi.Core.Scalar.Resolver; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace NBi.Testing.Core.Hierarchical.Json +{ + public class JsonPathStreamEngineTest + { + private class JsonPathStreamEngine : JsonPathFileEngine + { + private StreamReader StreamReader { get; } + + protected internal JsonPathStreamEngine(StreamReader streamReader, string from, IEnumerable selects) + : base(new LiteralScalarResolver(string.Empty), string.Empty, from, selects) + => StreamReader = streamReader; + + protected override TextReader GetTextReader(string filePath) + => StreamReader; + + protected override string EnsureFileExist() + => string.Empty; + } + + protected StreamReader GetResourceReader(string filename) + { + // A Stream is needed to read the XML document. + var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"{GetType().Namespace}.Resources.{filename}.json"); + var reader = new StreamReader(stream); + return reader; + } + + + [Test] + [TestCase("$.PurchaseOrders[*].Items[*]", 5)] + [TestCase("$.PurchaseOrders[*]", 4)] + public void Execute_Example_RowCount(string from, int rowCount) + { + var selects = new List() + { + new ElementSelect("$") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That(result.Count, Is.EqualTo(rowCount)); + } + } + + [Test] + public void Execute_Example_FirstColumnIsCorrect() + { + var from = "$.PurchaseOrders[*].Items[*]"; + var selects = new List() + { + new ElementSelect("PartNumber") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That(result.Count, Is.EqualTo(5)); + Assert.That(result.Select(x => ((x as IEnumerable).ElementAt(0) as string).Length), Is.All.EqualTo(6)); //Format is 123-XY + } + } + + [Test] + public void Execute_Example_AllColumnsAreCorrect() + { + var from = "$.PurchaseOrders[*].Items[*]"; + var selects = new List() + { + new ElementSelect("PartNumber"), + new ElementSelect("Quantity") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That(result.Count, Is.EqualTo(5)); + Assert.That(result.Count, Is.EqualTo(5)); + Assert.That(result.Select(x => ((x as IEnumerable).ElementAt(0) as string).Length), Is.All.EqualTo(6)); //Format is 123-XY + Assert.That(result.Select(x => (x as IEnumerable).ElementAt(1)), Is.All.EqualTo(1).Or.EqualTo(2)); //All quantity are between 1 and 2 + } + } + + + [Test] + public void Execute_FromElement_ValueCorrect() + { + var from = "$.PurchaseOrders[*].Items[*].ProductName"; + var selects = new List() + { + new ElementSelect("$") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); + } + } + + [Test] + public void Execute_FromAttribute_ValueCorrect() + { + var from = "$.PurchaseOrders[*].Items[*]"; + var selects = new List() + { + new ElementSelect("$.PartNumber") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); + } + } + + [Test] + public void Execute_MissingElement_Null() + { + var from = "$.PurchaseOrders[*]"; + var selects = new List() + { + new ElementSelect("$.PurchaseOrderNumber") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That((result.ElementAt(3) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); + } + } + + [Test] + public void Execute_ParentElement_ValueCorrect() + { + var from = "$.PurchaseOrders[*].Items[*]"; + var selects = new List() + { + new ElementSelect("!!.PurchaseOrderNumber"), + new ElementSelect("$.PartNumber") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("99503")); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); + + Assert.That((result.ElementAt(1) as IEnumerable).ElementAt(0), Does.Contain("99503")); + Assert.That((result.ElementAt(1) as IEnumerable).ElementAt(1), Does.Contain("926-AA")); + + Assert.That((result.ElementAt(2) as IEnumerable).ElementAt(0), Does.Contain("99505")); + Assert.That((result.ElementAt(2) as IEnumerable).ElementAt(1), Does.Contain("456-NM")); + } + } + + [Test] + public void Execute_ParentElementGoingAboveRoot_ValueCorrect() + { + var from = "$.PurchaseOrders[*].Items[*]"; + var selects = new List() + { + new ElementSelect("!!!!!!.PurchaseOrderNumber"), + new ElementSelect("$.PartNumber") + }; + + using (var reader = GetResourceReader("PurchaseOrders")) + { + var engine = new JsonPathStreamEngine(reader, from, selects); + var result = engine.Execute(); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("(null)")); + Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); + + Assert.That((result.ElementAt(1) as IEnumerable).ElementAt(0), Does.Contain("(null)")); + Assert.That((result.ElementAt(1) as IEnumerable).ElementAt(1), Does.Contain("926-AA")); + + Assert.That((result.ElementAt(2) as IEnumerable).ElementAt(0), Does.Contain("(null)")); + Assert.That((result.ElementAt(2) as IEnumerable).ElementAt(1), Does.Contain("456-NM")); + } + } + } +} diff --git a/NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json b/NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json new file mode 100644 index 000000000..070026091 --- /dev/null +++ b/NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json @@ -0,0 +1,146 @@ +{ + "PurchaseOrders": [ + { + "PurchaseOrderNumber": "99503", + "OrderDate": "1999-10-20", + "Address": [ + { + "Name": "Ellen Adams", + "Street": "123 Maple Street", + "City": "Mill Valley", + "State": "CA", + "Zip": "10999", + "Country": "USA" + }, + { + "Name": "Tai Yee", + "Street": "8 Oak Avenue", + "City": "Old Town", + "State": "PA", + "Zip": "95819", + "Country": "USA" + } + ], + "DeliveryNotes": "Please leave packages in shed by driveway.", + "Items": [ + { + "PartNumber": "872-AA", + "ProductName": "Lawnmower", + "Quantity": 1, + "USPrice": 148.95, + "Comment": "Confirm this is electric" + }, + { + "PartNumber": "926-AA", + "ProductName": "Baby Monitor", + "Quantity": 2, + "USPrice": 39.98, + "ShipDate": "1999-05-21" + } + ] + }, + { + "PurchaseOrderNumber": "99505", + "OrderDate": "1999-10-22", + "Address": [ + { + "Name": "Cristian Osorio", + "Street": "456 Main Street", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + }, + { + "Name": "Cristian Osorio", + "Street": "456 Main Street", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + } + ], + "DeliveryNotes": "Please notify by email before shipping.", + "Items": [ + { + "PartNumber": "456-NM", + "ProductName": "Power Supply", + "Quantity": 1, + "USPrice": 45.99 + } + ] + }, + { + "PurchaseOrderNumber": "99504", + "OrderDate": "1999-10-22", + "Address": [ + { + "Name": "Jessica Arnold", + "Street": "4055 Madison Ave", + "City": "Seattle", + "State": "WA", + "Zip": "98112", + "Country": "USA" + }, + { + "Name": "Jessica Arnold", + "Street": "4055 Madison Ave", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + } + ], + "DeliveryNotes": "Please do not deliver on Saturday.", + "Items": [ + { + "PartNumber": "898-AZ", + "ProductName": "Computer Keyboard", + "Quantity": 1, + "USPrice": 29.99 + }, + { + "PartNumber": "898-AM", + "ProductName": "Wireless Mouse", + "Quantity": 1, + "USPrice": 14.99 + } + ] + }, + { + "PONumber": "11223", + "Date": "2000-01-15", + "ShippingAddress": { + "Name": "Chris Preston", + "Street": "123 Main St.", + "City": "Seattle", + "State": "WA", + "Zip": "98113", + "Country": "USA" + }, + "BillingAddress": { + "Name": "Chris Preston", + "Street": "123 Main St.", + "City": "Seattle", + "State": "WA", + "Zip": "98113", + "Country": "USA" + }, + "DeliveryInstructions": "Ship only complete order.", + "Item": [ + { + "PartNum": "LIT-01", + "ProductID": "Litware Networking Card", + "Qty": 1, + "Price": 20.99 + }, + { + "PartNum": "LIT-25", + "ProductID": "Litware 17in LCD Monitor", + "Qty": 1, + "Price": 199.99 + } + ] + } + ] +} \ No newline at end of file diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index eecbae273..4d939b73e 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -125,6 +125,7 @@ + @@ -322,6 +323,9 @@ + + + From 1a7574269f600655ac10c6c64bce5f68197958d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 27 Oct 2019 17:45:46 +0100 Subject: [PATCH 03/57] Add xml syntax, support for path and url engines and acceptance tests --- .../Hierarchical/Json/JsonPathUrlEngine.cs | 37 +++++ NBi.Core/NBi.Core.csproj | 1 + .../Resolver/XPathResultSetResolver.cs | 8 +- .../Resolver/XPathResultSetResolverArgs.cs | 9 +- .../Helper/ResultSetResolverArgsBuilder.cs | 35 ++++- .../Helper/SequenceResolverArgsBuilder.cs | 11 +- ...ngineTest.cs => JsonPathFileEngineTest.cs} | 2 +- .../Json/JsonPathUrlEngineTest.cs | 47 ++++++ NBi.Testing.Core/NBi.Testing.Core.csproj | 3 +- .../Items/Hierarchical/JsonSourceXmlTest.cs | 116 ++++++++++++++ .../XmlSourceXmlTest.cs} | 6 +- NBi.Testing.Xml/NBi.Testing.Xml.csproj | 8 +- .../Resources/JsonSourceXmlTestSuite.xml | 24 +++ ...estSuite.xml => XmlSourceXmlTestSuite.xml} | 0 .../Resources/Csv/PurchaseOrders.json | 146 ++++++++++++++++++ .../Resources/Csv/PurchaseOrders.xml | 122 +++++++++++++++ .../Positive/ResultSetConstraint.nbits | 114 ++++++++++++++ NBi.Testing/NBi.Testing.csproj | 6 + NBi.Xml/Constraints/EqualToXml.cs | 2 +- .../Items/Hierarchical/Json/JsonFromXml.cs | 15 ++ .../Items/Hierarchical/Json/JsonPathXml.cs | 17 ++ .../Items/Hierarchical/Json/JsonSelectXml.cs | 15 ++ .../Items/Hierarchical/Json/JsonSourceXml.cs | 22 +++ .../Xml/DefaultNamespacePrefixXml.cs | 2 +- .../Items/{ => Hierarchical}/Xml/FromXml.cs | 2 +- .../Items/{ => Hierarchical}/Xml/SelectXml.cs | 2 +- .../Items/{ => Hierarchical}/Xml/XPathXml.cs | 10 +- .../{ => Hierarchical}/Xml/XmlSourceXml.cs | 2 +- NBi.Xml/NBi.Xml.csproj | 14 +- NBi.Xml/Schema/BaseType.xsd | 16 ++ NBi.Xml/Systems/ResultSetSystemXml.cs | 6 +- 31 files changed, 773 insertions(+), 47 deletions(-) create mode 100644 NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs rename NBi.Testing.Core/Hierarchical/Json/{JsonPathEngineTest.cs => JsonPathFileEngineTest.cs} (99%) create mode 100644 NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs create mode 100644 NBi.Testing.Xml/Items/Hierarchical/JsonSourceXmlTest.cs rename NBi.Testing.Xml/Items/{XmlSourceTest.cs => Hierarchical/XmlSourceXmlTest.cs} (97%) create mode 100644 NBi.Testing.Xml/Resources/JsonSourceXmlTestSuite.xml rename NBi.Testing.Xml/Resources/{XmlSourceTestSuite.xml => XmlSourceXmlTestSuite.xml} (100%) create mode 100644 NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.json create mode 100644 NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.xml create mode 100644 NBi.Xml/Items/Hierarchical/Json/JsonFromXml.cs create mode 100644 NBi.Xml/Items/Hierarchical/Json/JsonPathXml.cs create mode 100644 NBi.Xml/Items/Hierarchical/Json/JsonSelectXml.cs create mode 100644 NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs rename NBi.Xml/Items/{ => Hierarchical}/Xml/DefaultNamespacePrefixXml.cs (86%) rename NBi.Xml/Items/{ => Hierarchical}/Xml/FromXml.cs (86%) rename NBi.Xml/Items/{ => Hierarchical}/Xml/SelectXml.cs (91%) rename NBi.Xml/Items/{ => Hierarchical}/Xml/XPathXml.cs (70%) rename NBi.Xml/Items/{ => Hierarchical}/Xml/XmlSourceXml.cs (93%) diff --git a/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs new file mode 100644 index 000000000..4e21e3e4a --- /dev/null +++ b/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs @@ -0,0 +1,37 @@ +using NBi.Core.Scalar.Resolver; +using NBi.Extensibility; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net; + +namespace NBi.Core.Hierarchical.Json +{ + public class JsonPathUrlEngine : JsonPathEngine + { + public IScalarResolver Url { get; } + + public JsonPathUrlEngine(IScalarResolver url, string from, IEnumerable selects) + : base(from, selects) + => (Url) = (url); + + public override IEnumerable Execute() + { + var url = Url.Execute(); + var jsonText = GetRemoteContent(url); + var json = JToken.Parse(jsonText); + return Execute(json); + } + + protected virtual string GetRemoteContent(string url) + { + using (var webClient = new WebClient()) + return webClient.DownloadString(url); + } + } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 74910c537..d0211befe 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -250,6 +250,7 @@ + diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs index 3b9086826..9db498cd1 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs +++ b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs @@ -11,16 +11,14 @@ namespace NBi.Core.ResultSet.Resolver { class XPathResultSetResolver : IResultSetResolver { - private readonly XPathResultSetResolverArgs args; + private XPathResultSetResolverArgs Args { get; } public XPathResultSetResolver(XPathResultSetResolverArgs args) - { - this.args = args; - } + => Args = args; public virtual ResultSet Execute() { - var objects = args.XPathEngine.Execute(); + var objects = Args.XPathEngine.Execute(); var helper = new ObjectsToRowsHelper(); var rows = helper.Execute(objects); diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs index dd748ee13..a3827a11c 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs +++ b/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs @@ -6,16 +6,15 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using NBi.Core.Hierarchical; namespace NBi.Core.ResultSet.Resolver { public class XPathResultSetResolverArgs : ResultSetResolverArgs { - public XPathEngine XPathEngine { get; } + public AbstractPathEngine XPathEngine { get; } - public XPathResultSetResolverArgs(XPathEngine xpathEngine) - { - this.XPathEngine = xpathEngine; - } + public XPathResultSetResolverArgs(AbstractPathEngine xpathEngine) + => XPathEngine = xpathEngine; } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 198567be0..9dc64b1cd 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -8,7 +8,7 @@ using NBi.Xml.Items; using NBi.Xml.Items.ResultSet; using NBi.Xml.Items.ResultSet.Combination; -using NBi.Xml.Items.Xml; +using NBi.Xml.Items.Hierarchical.Xml; using NBi.Xml.Settings; using NBi.Xml.Systems; using NBi.Xml.Variables.Sequence; @@ -19,6 +19,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using NBi.Xml.Items.Hierarchical.Json; +using NBi.Core.Hierarchical.Json; namespace NBi.NUnit.Builder.Helper { @@ -65,6 +67,8 @@ public void Build() args = BuildSequenceResolverArgs((obj as ResultSetSystemXml).Sequence); else if ((obj as ResultSetSystemXml).XmlSource != null) args = BuildXPathResolverArgs((obj as ResultSetSystemXml).XmlSource); + else if ((obj as ResultSetSystemXml).JsonSource != null) + args = BuildJsonPathResolverArgs((obj as ResultSetSystemXml).JsonSource); //ResultSet (embedded) else if ((obj as ResultSetSystemXml).Rows != null) args = BuildEmbeddedResolverArgs((obj as ResultSetSystemXml).Content); @@ -98,6 +102,8 @@ public void Build() if (obj is XmlSourceXml) args = BuildXPathResolverArgs((obj as XmlSourceXml)); + if (obj is JsonSourceXml) + args = BuildJsonPathResolverArgs((obj as JsonSourceXml)); if (args == null) throw new ArgumentException(); @@ -203,6 +209,33 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) return new XPathResultSetResolverArgs(engine); } + private ResultSetResolverArgs BuildJsonPathResolverArgs(JsonSourceXml jsonSource) + { + Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceVerbose, "ResultSet defined through an json-source."); + + var selects = new List(); + var selectFactory = new HierarchicalSelectFactory(); + foreach (var select in jsonSource.JsonPath.Selects) + selects.Add(selectFactory.Instantiate(select.Value, null, false)); + + var helper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); + + + JsonPathEngine engine = null; + if (jsonSource.File != null) + { + var resolverPath = helper.InstantiateResolver(jsonSource.File.Path); + engine = new JsonPathFileEngine(resolverPath, settings?.BasePath, jsonSource.JsonPath.From.Value, selects); + } + else if (jsonSource.Url != null) + { + var resolverUrl = helper.InstantiateResolver(jsonSource.Url.Value); + engine = new JsonPathUrlEngine(resolverUrl, jsonSource.JsonPath.From.Value, selects); + } + + return new XPathResultSetResolverArgs(engine); + } + public ResultSetResolverArgs GetArgs() => args; } } diff --git a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs index 8422d2beb..44da149d9 100644 --- a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs @@ -1,21 +1,12 @@ -using NBi.Core; -using NBi.Core.Injection; +using NBi.Core.Injection; using NBi.Core.IO.Filtering; -using NBi.Core.Query; -using NBi.Core.Query.Resolver; using NBi.Core.ResultSet; -using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Duration; using NBi.Core.Scalar.Resolver; using NBi.Core.Sequence.Resolver; using NBi.Core.Sequence.Resolver.Loop; using NBi.Core.Variable; -using NBi.Core.Hierarchical.Xml; -using NBi.Xml.Items; -using NBi.Xml.Items.ResultSet; -using NBi.Xml.Items.Xml; using NBi.Xml.Settings; -using NBi.Xml.Systems; using NBi.Xml.Variables.Sequence; using System; using System.Collections.Generic; diff --git a/NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs b/NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs similarity index 99% rename from NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs rename to NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs index f8a05378a..2203660f2 100644 --- a/NBi.Testing.Core/Hierarchical/Json/JsonPathEngineTest.cs +++ b/NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs @@ -13,7 +13,7 @@ namespace NBi.Testing.Core.Hierarchical.Json { - public class JsonPathStreamEngineTest + public class JsonPathFileEngineTest { private class JsonPathStreamEngine : JsonPathFileEngine { diff --git a/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs b/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs new file mode 100644 index 000000000..1d02f78d0 --- /dev/null +++ b/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs @@ -0,0 +1,47 @@ +using NBi.Core.Hierarchical; +using NBi.Core.Hierarchical.Json; +using NBi.Core.Scalar.Resolver; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace NBi.Testing.Core.Hierarchical.Json +{ + public class JsonPathUrlEngineTest + { + private class StubJsonPathUrlEngine : JsonPathUrlEngine + { + public StubJsonPathUrlEngine(IScalarResolver url, string from, IEnumerable selects) + : base(url, from, selects) { } + + protected override string GetRemoteContent(string url) + { + using (var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"{GetType().Namespace}.Resources.{url}")) + using (var streamReader = new StreamReader(stream)) + return streamReader.ReadToEnd(); + } + } + + [Test] + [TestCase("$.PurchaseOrders[*].Items[*]", 5)] + [TestCase("$.PurchaseOrders[*]", 4)] + public void Execute_Example_RowCount(string from, int rowCount) + { + var selects = new List() + { + new ElementSelect("$") + }; + + var engine = new StubJsonPathUrlEngine(new LiteralScalarResolver("PurchaseOrders.json"), from, selects); + var result = engine.Execute(); + Assert.That(result.Count, Is.EqualTo(rowCount)); + } + } +} diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 4d939b73e..b7f42f822 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -125,7 +125,8 @@ - + + diff --git a/NBi.Testing.Xml/Items/Hierarchical/JsonSourceXmlTest.cs b/NBi.Testing.Xml/Items/Hierarchical/JsonSourceXmlTest.cs new file mode 100644 index 000000000..66212e286 --- /dev/null +++ b/NBi.Testing.Xml/Items/Hierarchical/JsonSourceXmlTest.cs @@ -0,0 +1,116 @@ +using System.IO; +using System.Reflection; +using NBi.Xml; +using NBi.Xml.Items; +using NBi.Xml.Items.Hierarchical.Json; +using NBi.Xml.Constraints; +using NUnit.Framework; +using System; + +namespace NBi.Testing.Xml.Unit.Items.Hierarchical +{ + public class JsonSourceXmlTest : BaseXmlTest + { + [Test] + public void Deserialize_SampleFile_XmlSource() + { + int testNr = 0; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + // Check the properties of the object. + Assert.That(ts.Tests[testNr].Constraints[0], Is.AssignableTo()); + Assert.That(((ts.Tests[testNr].Constraints[0]) as EqualToXml).ResultSet.JsonSource, Is.TypeOf()); + } + + [Test] + public void Deserialize_SampleFile_File() + { + int testNr = 0; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + // Check the properties of the object. + var jsonSource = ((ts.Tests[testNr].Constraints[0]) as EqualToXml).ResultSet.JsonSource; + Assert.That(jsonSource.File, Is.TypeOf()); + Assert.That(jsonSource.File.Path, Is.Not.Empty.And.Not.Null); + Assert.That(jsonSource.File.Path, Is.EqualTo("Myfile.json")); + } + + [Test] + public void Serialize_File_PathIsSet() + { + var root = new JsonSourceXml() + { + File = new FileXml + { + Path = "C:\\myPath.json" + } + }; + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain("")); + Assert.That(xml, Does.Contain("")); + Assert.That(xml, Does.Contain("C:\\myPath.json")); + Assert.That(xml, Does.Not.Contain("()); + } + + [Test] + public void Deserialize_SampleFile_XPathFrom() + { + int testNr = 0; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + // Check the properties of the object. + var jsonPath = ((ts.Tests[testNr].Constraints[0]) as EqualToXml).ResultSet.JsonSource.JsonPath; + Assert.That(jsonPath.From, Is.TypeOf()); + Assert.That(jsonPath.From.Value, Is.EqualTo("$.Path[*]")); + } + + [Test] + public void Deserialize_SampleFile_JsonPathSelects() + { + int testNr = 0; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + // Check the properties of the object. + var jsonPath = ((ts.Tests[testNr].Constraints[0]) as EqualToXml).ResultSet.JsonSource.JsonPath; + Assert.That(jsonPath.Selects, Is.Not.Null.And.Not.Empty); + Assert.That(jsonPath.Selects, Has.Count.EqualTo(2)); + } + + [Test] + public void Deserialize_SampleFile_XPathSelectElement() + { + int testNr = 0; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + // Check the properties of the object. + var selects = ((ts.Tests[testNr].Constraints[0]) as EqualToXml).ResultSet.JsonSource.JsonPath.Selects; + Assert.That(selects[0].Value, Is.EqualTo("$.Item.SubItem[*].Quantity")); + Assert.That(selects[1].Value, Is.EqualTo("!.Number")); + } + } +} diff --git a/NBi.Testing.Xml/Items/XmlSourceTest.cs b/NBi.Testing.Xml/Items/Hierarchical/XmlSourceXmlTest.cs similarity index 97% rename from NBi.Testing.Xml/Items/XmlSourceTest.cs rename to NBi.Testing.Xml/Items/Hierarchical/XmlSourceXmlTest.cs index ba416f9ff..edacbe3c1 100644 --- a/NBi.Testing.Xml/Items/XmlSourceTest.cs +++ b/NBi.Testing.Xml/Items/Hierarchical/XmlSourceXmlTest.cs @@ -2,14 +2,14 @@ using System.Reflection; using NBi.Xml; using NBi.Xml.Items; -using NBi.Xml.Items.Xml; +using NBi.Xml.Items.Hierarchical.Xml; using NBi.Xml.Constraints; using NUnit.Framework; using System; -namespace NBi.Testing.Xml.Unit.Items +namespace NBi.Testing.Xml.Unit.Items.Hierarchical { - public class XmlSourceTest : BaseXmlTest + public class XmlSourceXmlTest : BaseXmlTest { [Test] public void Deserialize_SampleFile_XmlSource() diff --git a/NBi.Testing.Xml/NBi.Testing.Xml.csproj b/NBi.Testing.Xml/NBi.Testing.Xml.csproj index 0fbe35db2..a6ebfdda0 100644 --- a/NBi.Testing.Xml/NBi.Testing.Xml.csproj +++ b/NBi.Testing.Xml/NBi.Testing.Xml.csproj @@ -89,6 +89,7 @@ + @@ -103,7 +104,7 @@ - + @@ -393,7 +394,7 @@ - + @@ -411,6 +412,9 @@ + + + diff --git a/NBi.Testing.Xml/Resources/JsonSourceXmlTestSuite.xml b/NBi.Testing.Xml/Resources/JsonSourceXmlTestSuite.xml new file mode 100644 index 000000000..e86d76301 --- /dev/null +++ b/NBi.Testing.Xml/Resources/JsonSourceXmlTestSuite.xml @@ -0,0 +1,24 @@ + + + + + + select * from table + + + + + + + Myfile.json + + $.Path[*] + + + + + + + + + \ No newline at end of file diff --git a/NBi.Testing.Xml/Resources/XmlSourceTestSuite.xml b/NBi.Testing.Xml/Resources/XmlSourceXmlTestSuite.xml similarity index 100% rename from NBi.Testing.Xml/Resources/XmlSourceTestSuite.xml rename to NBi.Testing.Xml/Resources/XmlSourceXmlTestSuite.xml diff --git a/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.json b/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.json new file mode 100644 index 000000000..070026091 --- /dev/null +++ b/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.json @@ -0,0 +1,146 @@ +{ + "PurchaseOrders": [ + { + "PurchaseOrderNumber": "99503", + "OrderDate": "1999-10-20", + "Address": [ + { + "Name": "Ellen Adams", + "Street": "123 Maple Street", + "City": "Mill Valley", + "State": "CA", + "Zip": "10999", + "Country": "USA" + }, + { + "Name": "Tai Yee", + "Street": "8 Oak Avenue", + "City": "Old Town", + "State": "PA", + "Zip": "95819", + "Country": "USA" + } + ], + "DeliveryNotes": "Please leave packages in shed by driveway.", + "Items": [ + { + "PartNumber": "872-AA", + "ProductName": "Lawnmower", + "Quantity": 1, + "USPrice": 148.95, + "Comment": "Confirm this is electric" + }, + { + "PartNumber": "926-AA", + "ProductName": "Baby Monitor", + "Quantity": 2, + "USPrice": 39.98, + "ShipDate": "1999-05-21" + } + ] + }, + { + "PurchaseOrderNumber": "99505", + "OrderDate": "1999-10-22", + "Address": [ + { + "Name": "Cristian Osorio", + "Street": "456 Main Street", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + }, + { + "Name": "Cristian Osorio", + "Street": "456 Main Street", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + } + ], + "DeliveryNotes": "Please notify by email before shipping.", + "Items": [ + { + "PartNumber": "456-NM", + "ProductName": "Power Supply", + "Quantity": 1, + "USPrice": 45.99 + } + ] + }, + { + "PurchaseOrderNumber": "99504", + "OrderDate": "1999-10-22", + "Address": [ + { + "Name": "Jessica Arnold", + "Street": "4055 Madison Ave", + "City": "Seattle", + "State": "WA", + "Zip": "98112", + "Country": "USA" + }, + { + "Name": "Jessica Arnold", + "Street": "4055 Madison Ave", + "City": "Buffalo", + "State": "NY", + "Zip": "98112", + "Country": "USA" + } + ], + "DeliveryNotes": "Please do not deliver on Saturday.", + "Items": [ + { + "PartNumber": "898-AZ", + "ProductName": "Computer Keyboard", + "Quantity": 1, + "USPrice": 29.99 + }, + { + "PartNumber": "898-AM", + "ProductName": "Wireless Mouse", + "Quantity": 1, + "USPrice": 14.99 + } + ] + }, + { + "PONumber": "11223", + "Date": "2000-01-15", + "ShippingAddress": { + "Name": "Chris Preston", + "Street": "123 Main St.", + "City": "Seattle", + "State": "WA", + "Zip": "98113", + "Country": "USA" + }, + "BillingAddress": { + "Name": "Chris Preston", + "Street": "123 Main St.", + "City": "Seattle", + "State": "WA", + "Zip": "98113", + "Country": "USA" + }, + "DeliveryInstructions": "Ship only complete order.", + "Item": [ + { + "PartNum": "LIT-01", + "ProductID": "Litware Networking Card", + "Qty": 1, + "Price": 20.99 + }, + { + "PartNum": "LIT-25", + "ProductID": "Litware 17in LCD Monitor", + "Qty": 1, + "Price": 199.99 + } + ] + } + ] +} \ No newline at end of file diff --git a/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.xml b/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.xml new file mode 100644 index 000000000..2ea8b1bd4 --- /dev/null +++ b/NBi.Testing/Acceptance/Resources/Csv/PurchaseOrders.xml @@ -0,0 +1,122 @@ + + + +
+ Ellen Adams + 123 Maple Street + Mill Valley + CA + 10999 + USA +
+
+ Tai Yee + 8 Oak Avenue + Old Town + PA + 95819 + USA +
+ Please leave packages in shed by driveway. + + + Lawnmower + 1 + 148.95 + Confirm this is electric + + + Baby Monitor + 2 + 39.98 + 1999-05-21 + + +
+ +
+ Cristian Osorio + 456 Main Street + Buffalo + NY + 98112 + USA +
+
+ Cristian Osorio + 456 Main Street + Buffalo + NY + 98112 + USA +
+ Please notify by email before shipping. + + + Power Supply + 1 + 45.99 + + +
+ +
+ Jessica Arnold + 4055 Madison Ave + Seattle + WA + 98112 + USA +
+
+ Jessica Arnold + 4055 Madison Ave + Buffalo + NY + 98112 + USA +
+ Please do not deliver on Saturday. + + + Computer Keyboard + 1 + 29.99 + + + Wireless Mouse + 1 + 14.99 + + +
+ + + Chris Preston + 123 Main St. + Seattle + WA + 98113 + USA + + + Chris Preston + 123 Main St. + Seattle + WA + 98113 + USA + + Ship only complete order. + + Litware Networking Card + 1 + 20.99 + + + Litware 17in LCD Monitor + 1 + 199.99 + + +
diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 12cb81ce3..ac36516ec 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -521,6 +521,120 @@ + + + + + ..\Csv\PurchaseOrders.xml + + //PurchaseOrder/Items/Item + + + + + + + + + + + 99503 + 872-AA + + + 99503 + 926-AA + + + 99505 + 456-NM + + + 99504 + 898-AZ + + + 99504 + 898-AM + + + + + + + + + + ..\Csv\PurchaseOrders.json + + $.PurchaseOrders[*].Items[*] + + + + + + + + + + + 99503 + 872-AA + + + 99503 + 926-AA + + + 99505 + 456-NM + + + 99504 + 898-AZ + + + 99504 + 898-AM + + + + + + + + + + https://raw.githubusercontent.com/sitepoint-editors/json-examples/master/src/db.json + + $.clients[*] + + + + + + + + + + Dunlap Hubbard + + + Kirsten Sellers + + + Acosta Robbins + + + Lawrence Morrison + + + Trudy Bennett + + + + + diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 26b0e2d80..0495b5af1 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -516,6 +516,9 @@ Always + + Always + Always @@ -781,6 +784,9 @@ Always
+ + Always + Always diff --git a/NBi.Xml/Constraints/EqualToXml.cs b/NBi.Xml/Constraints/EqualToXml.cs index f7395e1c2..08df6fd68 100644 --- a/NBi.Xml/Constraints/EqualToXml.cs +++ b/NBi.Xml/Constraints/EqualToXml.cs @@ -9,7 +9,7 @@ using NBi.Xml.Items; using NBi.Xml.Items.ResultSet; using NBi.Xml.Settings; -using NBi.Xml.Items.Xml; +using NBi.Xml.Items.Hierarchical.Xml; using NBi.Core.ResultSet.Equivalence; using NBi.Core.Query.Client; using NBi.Xml.Systems; diff --git a/NBi.Xml/Items/Hierarchical/Json/JsonFromXml.cs b/NBi.Xml/Items/Hierarchical/Json/JsonFromXml.cs new file mode 100644 index 000000000..22f3a287b --- /dev/null +++ b/NBi.Xml/Items/Hierarchical/Json/JsonFromXml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Hierarchical.Json +{ + public class JsonFromXml + { + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Hierarchical/Json/JsonPathXml.cs b/NBi.Xml/Items/Hierarchical/Json/JsonPathXml.cs new file mode 100644 index 000000000..5efcabb92 --- /dev/null +++ b/NBi.Xml/Items/Hierarchical/Json/JsonPathXml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Hierarchical.Json +{ + public class JsonPathXml + { + [XmlElement("from")] + public JsonFromXml From { get; set; } + [XmlElement("select")] + public List Selects { get; set; } = new List(); + } +} diff --git a/NBi.Xml/Items/Hierarchical/Json/JsonSelectXml.cs b/NBi.Xml/Items/Hierarchical/Json/JsonSelectXml.cs new file mode 100644 index 000000000..0eb280fa5 --- /dev/null +++ b/NBi.Xml/Items/Hierarchical/Json/JsonSelectXml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Hierarchical.Json +{ + public class JsonSelectXml + { + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs b/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs new file mode 100644 index 000000000..8539f4f01 --- /dev/null +++ b/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Hierarchical.Json +{ + public class JsonSourceXml : BaseItem + { + [XmlElement("file")] + public FileXml File { get; set; } + + [XmlElement("url")] + public UrlXml Url { get; set; } + + [XmlElement("json-path")] + public JsonPathXml JsonPath { get; set; } + } +} diff --git a/NBi.Xml/Items/Xml/DefaultNamespacePrefixXml.cs b/NBi.Xml/Items/Hierarchical/Xml/DefaultNamespacePrefixXml.cs similarity index 86% rename from NBi.Xml/Items/Xml/DefaultNamespacePrefixXml.cs rename to NBi.Xml/Items/Hierarchical/Xml/DefaultNamespacePrefixXml.cs index 4de74f35e..d4ff4eeec 100644 --- a/NBi.Xml/Items/Xml/DefaultNamespacePrefixXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/DefaultNamespacePrefixXml.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace NBi.Xml.Items.Xml +namespace NBi.Xml.Items.Hierarchical.Xml { public class DefaultNamespacePrefixXml { diff --git a/NBi.Xml/Items/Xml/FromXml.cs b/NBi.Xml/Items/Hierarchical/Xml/FromXml.cs similarity index 86% rename from NBi.Xml/Items/Xml/FromXml.cs rename to NBi.Xml/Items/Hierarchical/Xml/FromXml.cs index 474ffc2ec..13ad7ee4e 100644 --- a/NBi.Xml/Items/Xml/FromXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/FromXml.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace NBi.Xml.Items.Xml +namespace NBi.Xml.Items.Hierarchical.Xml { public class FromXml { diff --git a/NBi.Xml/Items/Xml/SelectXml.cs b/NBi.Xml/Items/Hierarchical/Xml/SelectXml.cs similarity index 91% rename from NBi.Xml/Items/Xml/SelectXml.cs rename to NBi.Xml/Items/Hierarchical/Xml/SelectXml.cs index 0556d942f..978bcceeb 100644 --- a/NBi.Xml/Items/Xml/SelectXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/SelectXml.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace NBi.Xml.Items.Xml +namespace NBi.Xml.Items.Hierarchical.Xml { public class SelectXml { diff --git a/NBi.Xml/Items/Xml/XPathXml.cs b/NBi.Xml/Items/Hierarchical/Xml/XPathXml.cs similarity index 70% rename from NBi.Xml/Items/Xml/XPathXml.cs rename to NBi.Xml/Items/Hierarchical/Xml/XPathXml.cs index 6b2f1112f..50e354761 100644 --- a/NBi.Xml/Items/Xml/XPathXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/XPathXml.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace NBi.Xml.Items.Xml +namespace NBi.Xml.Items.Hierarchical.Xml { public class XPathXml { @@ -14,12 +14,6 @@ public class XPathXml [XmlElement("from")] public FromXml From { get; set; } [XmlElement("select")] - public List Selects { get; set; } - - public XPathXml() - { - Selects = new List(); - } - + public List Selects { get; set; } = new List(); } } diff --git a/NBi.Xml/Items/Xml/XmlSourceXml.cs b/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs similarity index 93% rename from NBi.Xml/Items/Xml/XmlSourceXml.cs rename to NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs index 7db6f8748..32e66e5f5 100644 --- a/NBi.Xml/Items/Xml/XmlSourceXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace NBi.Xml.Items.Xml +namespace NBi.Xml.Items.Hierarchical.Xml { public class XmlSourceXml : BaseItem { diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 9be4b90c4..354504198 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -176,6 +176,10 @@ + + + + @@ -251,11 +255,11 @@ - - - - - + + + + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index e27134d2c..fb33c6391 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -768,6 +768,12 @@ + + + + + + @@ -778,6 +784,15 @@ + + + + + + + + + @@ -1537,6 +1552,7 @@ + diff --git a/NBi.Xml/Systems/ResultSetSystemXml.cs b/NBi.Xml/Systems/ResultSetSystemXml.cs index 473c9a68f..5d15ff979 100644 --- a/NBi.Xml/Systems/ResultSetSystemXml.cs +++ b/NBi.Xml/Systems/ResultSetSystemXml.cs @@ -20,7 +20,8 @@ using NBi.Xml.Items.Alteration.Projection; using NBi.Xml.Items.Alteration.Lookup; using NBi.Xml.Variables.Sequence; -using NBi.Xml.Items.Xml; +using NBi.Xml.Items.Hierarchical.Xml; +using NBi.Xml.Items.Hierarchical.Json; namespace NBi.Xml.Systems { @@ -106,6 +107,9 @@ public override BaseItem BaseItem [XmlElement("xml-source")] public virtual XmlSourceXml XmlSource { get; set; } + [XmlElement("json-source")] + public virtual JsonSourceXml JsonSource { get; set; } + [XmlIgnore] public bool SequenceCombinationSpecified { get => SequenceCombination != null; set { } } From 51e1937f5ee50ac560e6326cb5c3b5a5d5ec7934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 29 Oct 2019 21:14:40 +0100 Subject: [PATCH 04/57] Implement the RestEngine and its authorizations --- NBi.Core/Api/Authentication/Anonymous.cs | 14 ++++ NBi.Core/Api/Authentication/ApiKey.cs | 39 +++++++++++ NBi.Core/Api/Authentication/HttpBasic.cs | 22 +++++++ .../Api/Authentication/IAuthentication.cs | 14 ++++ .../Api/Authentication/NtlmCurrentUser.cs | 19 ++++++ .../Api/Authentication/NtlmUserPassword.cs | 22 +++++++ NBi.Core/Api/Authentication/OAuth2.cs | 24 +++++++ NBi.Core/Api/Rest/HeaderRest.cs | 18 +++++ NBi.Core/Api/Rest/ParameterRest.cs | 18 +++++ NBi.Core/Api/Rest/RestEngine.cs | 47 ++++++++++++++ NBi.Core/Api/Rest/SegmentRest.cs | 18 +++++ NBi.Core/NBi.Core.csproj | 15 +++++ NBi.Core/packages.config | 1 + NBi.Testing.Core/Api/Rest/RestEngineTest.cs | 65 +++++++++++++++++++ NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + 15 files changed, 337 insertions(+) create mode 100644 NBi.Core/Api/Authentication/Anonymous.cs create mode 100644 NBi.Core/Api/Authentication/ApiKey.cs create mode 100644 NBi.Core/Api/Authentication/HttpBasic.cs create mode 100644 NBi.Core/Api/Authentication/IAuthentication.cs create mode 100644 NBi.Core/Api/Authentication/NtlmCurrentUser.cs create mode 100644 NBi.Core/Api/Authentication/NtlmUserPassword.cs create mode 100644 NBi.Core/Api/Authentication/OAuth2.cs create mode 100644 NBi.Core/Api/Rest/HeaderRest.cs create mode 100644 NBi.Core/Api/Rest/ParameterRest.cs create mode 100644 NBi.Core/Api/Rest/RestEngine.cs create mode 100644 NBi.Core/Api/Rest/SegmentRest.cs create mode 100644 NBi.Testing.Core/Api/Rest/RestEngineTest.cs diff --git a/NBi.Core/Api/Authentication/Anonymous.cs b/NBi.Core/Api/Authentication/Anonymous.cs new file mode 100644 index 000000000..1400fc129 --- /dev/null +++ b/NBi.Core/Api/Authentication/Anonymous.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RestSharp.Authenticators; + +namespace NBi.Core.Api.Authentication +{ + class Anonymous : IAuthentication + { + public IAuthenticator GetAuthenticator() => null; + } +} diff --git a/NBi.Core/Api/Authentication/ApiKey.cs b/NBi.Core/Api/Authentication/ApiKey.cs new file mode 100644 index 000000000..3861f7ad6 --- /dev/null +++ b/NBi.Core/Api/Authentication/ApiKey.cs @@ -0,0 +1,39 @@ +using NBi.Core.Scalar.Resolver; +using RestSharp; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + class ApiKey + { + public IScalarResolver Name { get; } + public IScalarResolver Value { get; } + + public ApiKey(IScalarResolver name, IScalarResolver value) + => (Name, Value) = (name, value); + + public ApiKey(IScalarResolver value) + : this(new LiteralScalarResolver("apiKey"), value) { } + + public IAuthenticator GetAuthenticator() => new ApiKeyAuthenticator(Name.Execute(), Value.Execute()); + + public class ApiKeyAuthenticator : IAuthenticator + { + public string Name { get; } + public string Value { get; } + + public ApiKeyAuthenticator(string name, string value) + => (Name, Value) = (name, value); + + public void Authenticate(IRestClient client, IRestRequest request) + { + request.AddHeader(Name, Value); + } + } + } +} diff --git a/NBi.Core/Api/Authentication/HttpBasic.cs b/NBi.Core/Api/Authentication/HttpBasic.cs new file mode 100644 index 000000000..c05afa11d --- /dev/null +++ b/NBi.Core/Api/Authentication/HttpBasic.cs @@ -0,0 +1,22 @@ +using NBi.Core.Scalar.Resolver; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + class HttpBasic : IAuthentication + { + public IScalarResolver Username { get; } + public IScalarResolver Password { get; } + + public HttpBasic(IScalarResolver username, IScalarResolver password) + => (Username, Password) = (username, password); + + public IAuthenticator GetAuthenticator() => new HttpBasicAuthenticator(Username.Execute(), Password.Execute()); + } + +} diff --git a/NBi.Core/Api/Authentication/IAuthentication.cs b/NBi.Core/Api/Authentication/IAuthentication.cs new file mode 100644 index 000000000..ff5f591ee --- /dev/null +++ b/NBi.Core/Api/Authentication/IAuthentication.cs @@ -0,0 +1,14 @@ +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + public interface IAuthentication + { + IAuthenticator GetAuthenticator(); + } +} diff --git a/NBi.Core/Api/Authentication/NtlmCurrentUser.cs b/NBi.Core/Api/Authentication/NtlmCurrentUser.cs new file mode 100644 index 000000000..966a5106b --- /dev/null +++ b/NBi.Core/Api/Authentication/NtlmCurrentUser.cs @@ -0,0 +1,19 @@ +using NBi.Core.Scalar.Resolver; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + class NtlmCurrentUser : IAuthentication + { + public NtlmCurrentUser() + { } + + public IAuthenticator GetAuthenticator() => new NtlmAuthenticator(); + } + +} diff --git a/NBi.Core/Api/Authentication/NtlmUserPassword.cs b/NBi.Core/Api/Authentication/NtlmUserPassword.cs new file mode 100644 index 000000000..2b89fac5c --- /dev/null +++ b/NBi.Core/Api/Authentication/NtlmUserPassword.cs @@ -0,0 +1,22 @@ +using NBi.Core.Scalar.Resolver; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + class NtlmUserPassword : IAuthentication + { + public IScalarResolver Username { get; } + public IScalarResolver Password { get; } + + public NtlmUserPassword(IScalarResolver username, IScalarResolver password) + => (Username, Password) = (username, password); + + public IAuthenticator GetAuthenticator() => new NtlmAuthenticator(Username.Execute(), Password.Execute()); + } + +} diff --git a/NBi.Core/Api/Authentication/OAuth2.cs b/NBi.Core/Api/Authentication/OAuth2.cs new file mode 100644 index 000000000..fe56afbfa --- /dev/null +++ b/NBi.Core/Api/Authentication/OAuth2.cs @@ -0,0 +1,24 @@ +using NBi.Core.Scalar.Resolver; +using RestSharp.Authenticators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Authentication +{ + class OAuth2 : IAuthentication + { + public IScalarResolver AccessToken { get; } + public IScalarResolver TokenType { get; } + + public OAuth2(IScalarResolver accessToken, IScalarResolver tokenType) + => (AccessToken, TokenType) = (accessToken, tokenType); + + public OAuth2(IScalarResolver accessToken) + : this(accessToken, new LiteralScalarResolver("OAuth")) { } + + public IAuthenticator GetAuthenticator() => new OAuth2AuthorizationRequestHeaderAuthenticator(AccessToken.Execute(), TokenType.Execute()); + } +} diff --git a/NBi.Core/Api/Rest/HeaderRest.cs b/NBi.Core/Api/Rest/HeaderRest.cs new file mode 100644 index 000000000..9df1b86a7 --- /dev/null +++ b/NBi.Core/Api/Rest/HeaderRest.cs @@ -0,0 +1,18 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Rest +{ + class HeaderRest + { + public IScalarResolver Name { get; } + public IScalarResolver Value { get; } + + public HeaderRest(IScalarResolver name, IScalarResolver value) + => (Name, Value) = (name, value); + } +} diff --git a/NBi.Core/Api/Rest/ParameterRest.cs b/NBi.Core/Api/Rest/ParameterRest.cs new file mode 100644 index 000000000..8fb74c31a --- /dev/null +++ b/NBi.Core/Api/Rest/ParameterRest.cs @@ -0,0 +1,18 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Rest +{ + class ParameterRest + { + public IScalarResolver Name { get; } + public IScalarResolver Value { get; } + + public ParameterRest(IScalarResolver name, IScalarResolver value) + => (Name, Value) = (name, value); + } +} diff --git a/NBi.Core/Api/Rest/RestEngine.cs b/NBi.Core/Api/Rest/RestEngine.cs new file mode 100644 index 000000000..7b62c9c27 --- /dev/null +++ b/NBi.Core/Api/Rest/RestEngine.cs @@ -0,0 +1,47 @@ +using NBi.Core.Api.Authentication; +using NBi.Core.Scalar.Resolver; +using RestSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Rest +{ + class RestEngine + { + public IAuthentication Authentication { get; } + public IScalarResolver BaseUrl { get; } + public IScalarResolver Path { get; } + public IEnumerable Parameters { get; } + public IEnumerable Segments { get; } = Array.Empty(); + public IEnumerable Headers { get; } = Array.Empty(); + + public RestEngine(IAuthentication authentication, IScalarResolver baseUrl, IScalarResolver path, IEnumerable parameters, IEnumerable segments, IEnumerable headers) + => (Authentication, BaseUrl, Path, Parameters, Segments, Headers) = (authentication, baseUrl, path, parameters ?? Array.Empty(), segments ?? Array.Empty(), headers ?? Array.Empty()); + + public string Execute() + { + var baseUrl = BaseUrl.Execute(); + var client = new RestClient(baseUrl) + { + Authenticator = Authentication.GetAuthenticator() + }; + var path = Path?.Execute() ?? string.Empty; + var request = new RestRequest(path, Method.GET); + + foreach (var parameter in Parameters) + request.AddParameter(parameter.Name.Execute(), parameter.Value.Execute()); + + foreach (var segment in Segments) + request.AddUrlSegment(segment.Name.Execute(), segment.Value.Execute()); + + foreach (var header in Headers) + request.AddHeader(header.Name.Execute(), header.Value.Execute()); + + var response = client.Execute(request); + return response.Content; + } + } +} diff --git a/NBi.Core/Api/Rest/SegmentRest.cs b/NBi.Core/Api/Rest/SegmentRest.cs new file mode 100644 index 000000000..86be18ce2 --- /dev/null +++ b/NBi.Core/Api/Rest/SegmentRest.cs @@ -0,0 +1,18 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Api.Rest +{ + class SegmentRest + { + public IScalarResolver Name { get; } + public IScalarResolver Value { get; } + + public SegmentRest(IScalarResolver name, IScalarResolver value) + => (Name, Value) = (name, value); + } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index d0211befe..69c4ec5c5 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -84,6 +84,9 @@ ..\packages\PocketCsvReader.1.0.0\lib\net461\PocketCsvReader.dll + + ..\packages\RestSharp.106.6.10\lib\net452\RestSharp.dll + @@ -98,6 +101,7 @@ ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + @@ -119,6 +123,17 @@ + + + + + + + + + + + diff --git a/NBi.Core/packages.config b/NBi.Core/packages.config index ea0fe8995..2598af1d9 100644 --- a/NBi.Core/packages.config +++ b/NBi.Core/packages.config @@ -12,6 +12,7 @@ + diff --git a/NBi.Testing.Core/Api/Rest/RestEngineTest.cs b/NBi.Testing.Core/Api/Rest/RestEngineTest.cs new file mode 100644 index 000000000..3ca647fce --- /dev/null +++ b/NBi.Testing.Core/Api/Rest/RestEngineTest.cs @@ -0,0 +1,65 @@ +using NBi.Core.Api.Authentication; +using NBi.Core.Api.Rest; +using NBi.Core.Scalar.Resolver; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Api.Rest +{ + public class RestEngineTest + { + [Test] + public void Execute_OneParameter_CorrectResponse() + { + var baseUrl = new LiteralScalarResolver("https://api.agify.io/"); + var parameter = new ParameterRest( + new LiteralScalarResolver("name"), + new LiteralScalarResolver("cedric") + ); + var engine = new RestEngine(new Anonymous(), baseUrl, null, new[] { parameter }, null, null); + var result = engine.Execute(); + Assert.That(result, Does.StartWith("{\"name\":\"cedric\",\"age\":")); + } + + [Test] + public void Execute_PathAndParameters_CorrectResponse() + { + var baseUrl = new LiteralScalarResolver("https://api.publicapis.org/"); + var path = new LiteralScalarResolver("entries"); + var parameter1 = new ParameterRest( + new LiteralScalarResolver("category"), + new LiteralScalarResolver("animals") + ); + var parameter2 = new ParameterRest( + new LiteralScalarResolver("https"), + new LiteralScalarResolver("true") + ); + var engine = new RestEngine(new Anonymous(), baseUrl, path, new[] { parameter1, parameter2 }, null, null); + var result = engine.Execute(); + Assert.That(result.Length, Is.GreaterThan(20)); + Assert.That(result, Does.StartWith("{\"count\":")); + } + + [Test] + public void Execute_Segments_CorrectResponse() + { + var baseUrl = new LiteralScalarResolver("https://verse.pawelad.xyz/"); + var path = new LiteralScalarResolver("/projects/{project}/"); + var segment = new SegmentRest( + new LiteralScalarResolver("project"), + new LiteralScalarResolver("jekyll") + ); + var parameter = new ParameterRest( + new LiteralScalarResolver("format"), + new LiteralScalarResolver("json") + ); + var engine = new RestEngine(new Anonymous(), baseUrl, path, new[] { parameter }, new[] { segment }, null); + var result = engine.Execute(); + Assert.That(result, Does.StartWith("{\"latest\":")); + } + } +} diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index b7f42f822..496929a58 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -86,6 +86,7 @@ Properties\AssemblyInfo.cs + From 8f59b93c65a5397a0a5f5fef6da48df82e156895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Wed, 30 Oct 2019 19:25:26 +0100 Subject: [PATCH 05/57] Serialization/deserialization of rest --- NBi.Testing.Xml/InstanceSettlingXmlTest.cs | 43 ++-- NBi.Testing.Xml/Items/Api/Rest/RestXmlTest.cs | 183 ++++++++++++++++++ NBi.Testing.Xml/NBi.Testing.Xml.csproj | 4 + .../Resources/RestXmlTestSuite.xml | 91 +++++++++ .../Items/Api/Authentication/AnonymousXml.cs | 11 ++ NBi.Xml/Items/Api/Authentication/ApiKeyXml.cs | 20 ++ .../Authentication/BaseAuthenticationXml.cs | 11 ++ .../Items/Api/Authentication/HttpBasicXml.cs | 19 ++ .../Api/Authentication/NtmlCurrentUserXml.cs | 11 ++ .../Api/Authentication/NtmlUserPasswordXml.cs | 19 ++ NBi.Xml/Items/Api/Authentication/OAuth2Xml.cs | 19 ++ NBi.Xml/Items/Api/Rest/AuthenticationXml.cs | 22 +++ NBi.Xml/Items/Api/Rest/RestHeaderXml.cs | 17 ++ NBi.Xml/Items/Api/Rest/RestParameterXml.cs | 17 ++ NBi.Xml/Items/Api/Rest/RestPathXml.cs | 14 ++ NBi.Xml/Items/Api/Rest/RestSegmentXml.cs | 17 ++ NBi.Xml/Items/Api/Rest/RestXml.cs | 36 ++++ .../Items/Hierarchical/Json/JsonSourceXml.cs | 6 +- NBi.Xml/NBi.Xml.csproj | 13 ++ NBi.Xml/Schema/BaseType.xsd | 68 +++++++ 20 files changed, 618 insertions(+), 23 deletions(-) create mode 100644 NBi.Testing.Xml/Items/Api/Rest/RestXmlTest.cs create mode 100644 NBi.Testing.Xml/Resources/RestXmlTestSuite.xml create mode 100644 NBi.Xml/Items/Api/Authentication/AnonymousXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/ApiKeyXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/BaseAuthenticationXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/HttpBasicXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/NtmlCurrentUserXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/NtmlUserPasswordXml.cs create mode 100644 NBi.Xml/Items/Api/Authentication/OAuth2Xml.cs create mode 100644 NBi.Xml/Items/Api/Rest/AuthenticationXml.cs create mode 100644 NBi.Xml/Items/Api/Rest/RestHeaderXml.cs create mode 100644 NBi.Xml/Items/Api/Rest/RestParameterXml.cs create mode 100644 NBi.Xml/Items/Api/Rest/RestPathXml.cs create mode 100644 NBi.Xml/Items/Api/Rest/RestSegmentXml.cs create mode 100644 NBi.Xml/Items/Api/Rest/RestXml.cs diff --git a/NBi.Testing.Xml/InstanceSettlingXmlTest.cs b/NBi.Testing.Xml/InstanceSettlingXmlTest.cs index 9fab9e4e1..d05f4314e 100644 --- a/NBi.Testing.Xml/InstanceSettlingXmlTest.cs +++ b/NBi.Testing.Xml/InstanceSettlingXmlTest.cs @@ -44,19 +44,19 @@ public void Serialize_TestWithInstanceSettling_InstanceSettlingCorrectlySerializ }; var serializer = new XmlSerializer(typeof(TestXml)); - var stream = new MemoryStream(); - var writer = new StreamWriter(stream, Encoding.UTF8); - serializer.Serialize(writer, test); - var content = Encoding.UTF8.GetString(stream.ToArray()); - writer.Close(); - stream.Close(); - - Debug.WriteLine(content); - - Assert.That(content, Does.Contain("()); + var resultSet = ts.Tests[testNr].Systems[0] as ResultSetSystemXml; + Assert.That(resultSet.JsonSource, Is.Not.Null); + var jsonSource = resultSet.JsonSource as JsonSourceXml; + Assert.That(jsonSource.Rest, Is.Not.Null); + } + + [Test] + public void Deserialize_TestUsingRestWithParameters_RestNotNull() + { + int testNr = 0; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Parameters, Is.Not.Null); + Assert.That(rest.Parameters, Has.Count.EqualTo(2)); + Assert.That(rest.Parameters.Any(x => x.Name == "parameter1")); + Assert.That(rest.Parameters.Any(x => x.Value == "value1")); + } + + [Test] + public void Deserialize_TestUsingRestWithHeaders_RestNotNull() + { + int testNr = 0; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Headers, Is.Not.Null); + Assert.That(rest.Headers, Has.Count.EqualTo(2)); + Assert.That(rest.Headers.Any(x => x.Name == "header1")); + Assert.That(rest.Headers.Any(x => x.Value == "value1")); + } + + [Test] + public void Deserialize_TestUsingRestWithSegment_RestNotNull() + { + int testNr = 0; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Segments, Is.Not.Null); + Assert.That(rest.Segments, Has.Count.EqualTo(2)); + Assert.That(rest.Segments.Any(x => x.Name == "segment1")); + Assert.That(rest.Segments.Any(x => x.Value == "value1")); + } + + [Test] + public void Deserialize_TestUsingRestWithoutAuthentication_AnonymousSelected() + { + int testNr = 0; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Authentication.Protocol, Is.TypeOf()); + } + + [Test] + public void Deserialize_TestUsingRestWithAnonyous_AnonymousValid() + { + int testNr = 1; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Authentication.Protocol, Is.TypeOf()); + } + + [Test] + public void Deserialize_TestUsingRestWithApiKey_ApiKeyValid() + { + int testNr = 2; + var ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var rest = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).JsonSource.Rest as RestXml; + Assert.That(rest.Authentication.Protocol, Is.TypeOf()); + var authentication = rest.Authentication.Protocol as ApiKeyXml; + Assert.That(authentication.Name, Is.EqualTo("apiKey")); + Assert.That(authentication.Value, Is.EqualTo("123456")); + } + + [Test] + public void Serialize_TestUsingRestWithAnonymous_AnonymousNotAdded() + { + var jsonSource = new JsonSourceXml + { + Rest = new RestXml + { + Authentication = new AuthenticationXml { Protocol = new AnonymousXml() }, + BaseAddress = "https://api.website.com", + Headers = new List() { new RestHeaderXml { Name = "rest-header-1", Value = "rh-val1" } }, + Path = new RestPathXml { Value = "v2/{user}/tags/{tag}" }, + Segments = new List() { new RestSegmentXml { Name = "user", Value = "xyz" }, new RestSegmentXml { Name = "tag", Value = "up" } }, + } + }; + + var serializer = new XmlSerializer(jsonSource.GetType()); + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream, Encoding.UTF8)) + { + serializer.Serialize(writer, jsonSource); + var content = Encoding.UTF8.GetString(stream.ToArray()); + + Debug.WriteLine(content); + + Assert.That(content, Does.Contain("")); + Assert.That(content, Does.Contain("v2/{user}/tags/{tag}")); + Assert.That(content, Does.Contain("")); + + Assert.That(content, Does.Contain(" + @@ -415,6 +416,9 @@ + + + diff --git a/NBi.Testing.Xml/Resources/RestXmlTestSuite.xml b/NBi.Testing.Xml/Resources/RestXmlTestSuite.xml new file mode 100644 index 000000000..217bc125a --- /dev/null +++ b/NBi.Testing.Xml/Resources/RestXmlTestSuite.xml @@ -0,0 +1,91 @@ + + + + + + + +
value1
+
value2
+ v2/user/{segment1}/project/{segment2} + value1 + value2 + value1 + value2 +
+ + $.[element] + + + +
+
+
+ + + + + Name + Value + + + + +
+ + + + + + + + + + + $.[element] + + + + + + + + + + + Name + Value + + + + + + + + + + + + 123456 + + + + $.[element] + + + + + + + + + + + Name + Value + + + + + +
\ No newline at end of file diff --git a/NBi.Xml/Items/Api/Authentication/AnonymousXml.cs b/NBi.Xml/Items/Api/Authentication/AnonymousXml.cs new file mode 100644 index 000000000..86f0bd884 --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/AnonymousXml.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class AnonymousXml : BaseAuthenticationXml + { } +} diff --git a/NBi.Xml/Items/Api/Authentication/ApiKeyXml.cs b/NBi.Xml/Items/Api/Authentication/ApiKeyXml.cs new file mode 100644 index 000000000..9aded083b --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/ApiKeyXml.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class ApiKeyXml : BaseAuthenticationXml + { + [XmlAttribute("name")] + [DefaultValue("apiKey")] + public string Name { get; set; } = "apiKey"; + + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Authentication/BaseAuthenticationXml.cs b/NBi.Xml/Items/Api/Authentication/BaseAuthenticationXml.cs new file mode 100644 index 000000000..cbd868697 --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/BaseAuthenticationXml.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Xml.Items.Api.Authentication +{ + public abstract class BaseAuthenticationXml + { } +} diff --git a/NBi.Xml/Items/Api/Authentication/HttpBasicXml.cs b/NBi.Xml/Items/Api/Authentication/HttpBasicXml.cs new file mode 100644 index 000000000..bbdfa81fc --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/HttpBasicXml.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class HttpBasicXml : BaseAuthenticationXml + { + [XmlAttribute("username")] + public string Username { get; set; } + + [XmlAttribute("password")] + public string Password { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Authentication/NtmlCurrentUserXml.cs b/NBi.Xml/Items/Api/Authentication/NtmlCurrentUserXml.cs new file mode 100644 index 000000000..dd25b61c8 --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/NtmlCurrentUserXml.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class NtmlCurrentUserXml : BaseAuthenticationXml + { } +} diff --git a/NBi.Xml/Items/Api/Authentication/NtmlUserPasswordXml.cs b/NBi.Xml/Items/Api/Authentication/NtmlUserPasswordXml.cs new file mode 100644 index 000000000..b8ef1c068 --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/NtmlUserPasswordXml.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class NtmlUserPasswordXml : BaseAuthenticationXml + { + [XmlAttribute("username")] + public string Username { get; set; } + + [XmlAttribute("password")] + public string Password { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Authentication/OAuth2Xml.cs b/NBi.Xml/Items/Api/Authentication/OAuth2Xml.cs new file mode 100644 index 000000000..6aafba199 --- /dev/null +++ b/NBi.Xml/Items/Api/Authentication/OAuth2Xml.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Authentication +{ + public class OAuth2Xml : BaseAuthenticationXml + { + [XmlElement("access-token")] + public string AccessToken { get; set; } + + [XmlAttribute("token-type")] + public string TokenType { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/AuthenticationXml.cs b/NBi.Xml/Items/Api/Rest/AuthenticationXml.cs new file mode 100644 index 000000000..7c180036b --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/AuthenticationXml.cs @@ -0,0 +1,22 @@ +using NBi.Xml.Items.Api.Authentication; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Rest +{ + public class AuthenticationXml + { + [XmlElement(Type = typeof(AnonymousXml), ElementName = "anonymous"), + XmlElement(Type = typeof(ApiKeyXml), ElementName = "api-key"), + XmlElement(Type = typeof(HttpBasicXml), ElementName = "http-basic"), + XmlElement(Type = typeof(NtmlCurrentUserXml), ElementName = "ntml-current-user"), + XmlElement(Type = typeof(NtmlUserPasswordXml), ElementName = "ntml"), + XmlElement(Type = typeof(OAuth2Xml), ElementName = "oauth2"), + ] + public BaseAuthenticationXml Protocol { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs b/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs new file mode 100644 index 000000000..72ac42645 --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using NBi.Core.Query; + +namespace NBi.Xml.Items +{ + public class RestHeaderXml + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestParameterXml.cs b/NBi.Xml/Items/Api/Rest/RestParameterXml.cs new file mode 100644 index 000000000..0b2bc698f --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/RestParameterXml.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using NBi.Core.Query; + +namespace NBi.Xml.Items +{ + public class RestParameterXml + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestPathXml.cs b/NBi.Xml/Items/Api/Rest/RestPathXml.cs new file mode 100644 index 000000000..49e154890 --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/RestPathXml.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using NBi.Core.Query; + +namespace NBi.Xml.Items +{ + public class RestPathXml + { + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs b/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs new file mode 100644 index 000000000..7f30eaecc --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using NBi.Core.Query; + +namespace NBi.Xml.Items +{ + public class RestSegmentXml + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlText] + public string Value { get; set; } + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestXml.cs b/NBi.Xml/Items/Api/Rest/RestXml.cs new file mode 100644 index 000000000..60e6f2341 --- /dev/null +++ b/NBi.Xml/Items/Api/Rest/RestXml.cs @@ -0,0 +1,36 @@ +using NBi.Xml.Items.Api.Authentication; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Api.Rest +{ + public class RestXml + { + [XmlAttribute("base-address")] + public string BaseAddress { get; set; } + + [XmlElement("authentication")] + public AuthenticationXml Authentication { get; set; } = new AuthenticationXml { Protocol = new AnonymousXml() }; + + public bool ShouldSerializeAuthentication() + => !(Authentication?.Protocol is AnonymousXml); + + [XmlElement("header")] + public List Headers { get; set; } = new List(); + + [XmlElement("path")] + public RestPathXml Path { get; set; } + + [XmlElement("segment")] + public List Segments { get; set; } = new List(); + + [XmlElement("parameter")] + public List Parameters { get; set; } = new List(); + + + } +} diff --git a/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs b/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs index 8539f4f01..94f7e5752 100644 --- a/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs +++ b/NBi.Xml/Items/Hierarchical/Json/JsonSourceXml.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Xml.Items.Api.Rest; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -16,6 +17,9 @@ public class JsonSourceXml : BaseItem [XmlElement("url")] public UrlXml Url { get; set; } + [XmlElement("rest")] + public RestXml Rest { get; set; } + [XmlElement("json-path")] public JsonPathXml JsonPath { get; set; } } diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 354504198..f6880473d 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -167,6 +167,19 @@ + + + + + + + + + + + + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index fb33c6391..357ab15f6 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -779,16 +779,84 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 44747e5e39938c3b41ae60bfdee043c9ac7c8269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 1 Nov 2019 22:06:36 +0100 Subject: [PATCH 06/57] Up to v2.7.1 for NUnit.Framework --- NBi.NUnit.Runtime/packages.config | 2 +- NBi.NUnit/packages.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NBi.NUnit.Runtime/packages.config b/NBi.NUnit.Runtime/packages.config index 22e0950ec..f21721f02 100644 --- a/NBi.NUnit.Runtime/packages.config +++ b/NBi.NUnit.Runtime/packages.config @@ -1,7 +1,7 @@  - + diff --git a/NBi.NUnit/packages.config b/NBi.NUnit/packages.config index 7a92ed65c..bb5c258e2 100644 --- a/NBi.NUnit/packages.config +++ b/NBi.NUnit/packages.config @@ -2,6 +2,6 @@ - + \ No newline at end of file From eedc14dfb3c2cd726d5e30be5a5bebb80ad1ee21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 1 Nov 2019 22:58:47 +0100 Subject: [PATCH 07/57] Change iconUrl by icon in nuspec files --- .../NBi.Extensibility/NBi.Extensibility.nuspec | 9 ++++++--- .../NBi.Framework.Tools.nuspec | 13 ++++++++----- .packages/NBi.Framework/NBi.Framework.nuspec | 13 ++++++++----- NBi-logo-white.jpg | Bin 6198 -> 0 bytes logo-2x.png | Bin 0 -> 2448 bytes 5 files changed, 22 insertions(+), 13 deletions(-) delete mode 100644 NBi-logo-white.jpg create mode 100644 logo-2x.png diff --git a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec index d07e39848..a4fd7076e 100644 --- a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec +++ b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec @@ -1,19 +1,22 @@ - + NBi.Extensibility $version$ Seddryck Seddryck Apache-2.0 https://github.com/Seddryck/NBi - https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png + images\logo-2x.png false Extensibility points of NBi. - This package contains the interfaces to implement to extend NBi features. Testing framework (add-on to NUnit) for Business Intelligence. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other solutions. + This package contains the interfaces to implement to extend NBi features. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. Check the release notes at https://github.com/Seddryck/NBi/releases/v$version$ Copyright 2013-$thisYear$ Test NBi SQL SSAS SSIS SSRS + + + \ No newline at end of file diff --git a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec index 9467b9708..16e4bbce5 100644 --- a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec +++ b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec @@ -1,22 +1,25 @@ - + NBi.Framework.Tools $version$ Seddryck Seddryck Apache-2.0 https://github.com/Seddryck/NBi - https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png + images\logo-2x.png false - This package contains the NBi framework and copy it to the tools folder. This package is not intended to be directly used by end-users. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio - This package contains the NBi framework and copy it to the tools folder. This package is not intended to be directly used by end-users. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual StudioTesting framework (add-on to NUnit) for Business Intelligence. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other solutions. + This package contains the NBi framework and copy it to the tools folder. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. + This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. Check the release notes at https://github.com/Seddryck/NBi/releases/v$version$ Copyright 2013-$thisYear$ Test NBi SQL SSAS SSIS SSRS - + $depList$ + + + \ No newline at end of file diff --git a/.packages/NBi.Framework/NBi.Framework.nuspec b/.packages/NBi.Framework/NBi.Framework.nuspec index cb4c992dd..ff7da9619 100644 --- a/.packages/NBi.Framework/NBi.Framework.nuspec +++ b/.packages/NBi.Framework/NBi.Framework.nuspec @@ -1,22 +1,25 @@ - + NBi.Framework $version$ Seddryck Seddryck Apache-2.0 https://github.com/Seddryck/NBi - https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png + images\logo-2x.png false - This package contains the NBi framework and references all the dll to your project. This package is not intended to be directly used by end-users. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio - This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual StudioTesting framework (add-on to NUnit) for Business Intelligence. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other solutions. + This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. + This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. Check the release notes at https://github.com/Seddryck/NBi/releases/v$version$ Copyright 2013-$thisYear$ Test NBi SQL SSAS SSIS SSRS - + $depList$ + + + \ No newline at end of file diff --git a/NBi-logo-white.jpg b/NBi-logo-white.jpg deleted file mode 100644 index c7cb23e9d15c70e7305adf524c9b43a55cc2b70f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6198 zcmbW5XEe(c2h3 zMsI^57%jH@exB#udmsDDe&2H)Yn>m~`f&Zu^Sb`)JpPxHmkYpkJuO`=fQXnFFub~e z%T|El8t?>2Cm~`0h#81T7>F)sfVTiSDH%B#DLFYAIRypzH7W*bDoRQ!7W(Tn4D2^J zIM{Bmv2yZ=@NwQ0#MR7_k#oRd#V_6|r^1SAe3qM)FlqNHM`re+3lv2k&M z{=0G6L6ipoL}Wz&1n}=5A||<77{xV8D(dS1F%by~F)0Zd87b-2m!Vhh08$1rMn0)~ zIN$tJBOfl+-j>dd7#3@Vxwj!Y_!T z;*zTBn%cVhZ{Hi*+B-VCx_eN)qhsUf3C!fwGARM$Vn%y)i)`mVM5j4(BnPn2 z)JXfP!`aam4s+PCcAixQBnn^#jEVjt1A+n*T7-joF^fV->@UgVr^7GhAAPuJ&>V8Ue*!^(rN!@(unjiSyW-M zDH1}TA*ua@J<>B5*E%H3gBxx~%AQd>9~&b4^m9tet|3d-zA1TU!2iG#6rQE5`#F*l z>cc}9?TqMyW;6^qjhlO_zeRXUQ%=&EsaiCH>M0X)V+}?FD_KPKayk;7%Bt`DQ@5+~ z(J?IwcX%nc^~?6%NHoT)wk3NZw5CK}fP-}|0n13<<$di3M_tW9#$PrK)??ptt@I{J zjN+E7>XPQ{IUCPDIxg<4q=~|<6kS^v=vo7e^J~LG<2&_PY|t5fsBov49g~9MPEGbO zIao&9Y1W7ie#ndRd$i6BO^W7O$HUN%=6_hq?1X77GKIEl#ti zT^IOkfqRO*d^izE`A@UKu7v4%?wqB&k=!vJkXIJ8{a(cbj4ea_kEYqy*t?Ydb{!od z*h8^c2NNXoEII}((C1I_#{Z-25$t(7NoC$3wr5ZZ2PfE@cdm)4`u>SMip*prf)uiicCF9-@hAn>(>{U zaCGfQ(g+E8>-ul$I>VJZKa~?GYJ=@nCGGVMc6s)dd@3*I&W8}Ps+L3cBin}t(vRd| zv-;xF5952axwv6R-D!?jjkt4evlyz}b|f`a#4eB?xQ|0VbQqllQ%*Em3?mBc^kat1KvJd8OR)mO*|075WO6_vx%oC3&>iJle4_c*nK5XJ1sOpr<>E(!uY}L5xpq3 za5thPEm}ysaGScGo>KYUXLx_x+98iU$=50p3l}^ZOqq!lb^<~Uje$vu3OL8y{^wT$ z!ULZ7kPeFLu+9GABjkBpTL+J-s+`X4{-D5iVDsSZ0c^j^aKwo<=keULUT8q#+9g2Z z-E{cE@4NHhDU7d0zVal!qm;9vDv2Kc?F=>aAUQ%?L4l1IlPuNc zwZH7Gf83DFwXwmO`Y^Dke^;ntL1t}vE<&uiLjbNh2^38B@HdCkZh9;_fNyz=4}Tn$ z8ki-?h-rq9Ta83yf20`i^`*paiOBDuX2yoj2kjlX<#<=nJUY|%8i5|P12u8tOuQ+I z%*)crN!sI9bKH~?|Ix^QOXXD}cZ%J08B@7k>NMj#R9g*yx-WAe#;9iU7mv(a-R$;z z5kdxcCq@;8*?W6FfVk|lk^(BdjX!fm%bi@znpZN09i-N$&i&{%vO^~NYvJyBrvF&E z2>Ws%CD&Owo-}O$wKuO*W+}go!_iGSz)c(9n(*uLv6JvIGeMJ6p)_dqthJJv#*xt7 zdwP1xX)E8+k|rrLT7MzL7Ed>vXVs?mJ3dlmf5TzwDiL~;JBUBTnP~QR4`4wQ&&)M5j3Qu?0h-C*;X3-c_+a} zvvVpF_BrBj(IaU;_rSmFuysrDk0)u*X001{9;5LPA9Dld;f&>W6sUY=vf}&F5C;cw+K=Ib{F-wb5jYtVQd%Y6caUmO-W2xUb0)?XSJ7 zX)ly4^gKZMh+7@ZG?fLX_IOu+<$+WbgO@KrSQ!ru#tmeC{m}gRui21E19wr?U+41c z9*a$NgN@Y2liOC`^*;*6@FqWwOXXj>z0J&!5R$q9^@Wu{A{tW~*Bf4)p8vQhzN%;B z_Sl0K%xQhz7<5Do=@zKYB1(7e<03+#7K;zifvJC*8gC02$v!NNwyFE%h7^L4KFz4M zYaa6=QPvPkcOFl%i+G7`1`V5+j3aOYzYTxw&B-dPm`cIYS5Swa#74DZJEu{ATvh~2@P#L@3*QmgO)xA=j|%;M3iUno0xTe z0X>->s=v;(8dFE>PWg64zMj960}*cJ^_LzSO%3Deh@bUC_%JY`~eV*Lui_t2E40I*oeP}AqtM`Y8i7-1-zsIxz*!+OqDys|D!^w@l7hhT85SrWbEpb)^epK=zls7qDDF3mO*la?~;WzF;Ph!Wl6Y%?6yTn+^3ODOB3cE=N#wrDy`n1u*!(d zDF8xs$d#h~#KjN}QT%xaYQ&H9j1xq?f4+lJ#UDDtPIqTE z>lkvaMGH^X+)%j8c!yE>v+-!rA3=f0Zviw1;szVFej2_?Ywu<Ev5niY+9x`K)Q%?-20oeYC4cCSk(6%~7n)~U(4U0tA` z*osW8(&|)ZyIGZ_jK7qNdIqOQx>3*k<@Kuixyh@1?z^~dwr;jAsaV3x(X21y^)2;a zE&Kh<)%nxeNxWKgGyRb!gvii zORVOb=!v8Dph_@g&9qhn#ZflAj|seek#{RM??Yg_=*{4shcE6Ctxl3@GtOG3V9qgz zvlrB~F_1#H2BoK1z}G&hfaxp5R6POYmm=Nx#I#2}g;AG{Sp9y~Tm>bc#Xa#C^Z?WS zLbk7{g2ran`F3X%n12)EKuGXVL_+DmD9=PVSbtZh<|+n3OQ8N_hA$u#VK+=**9Pe} zpPk9g&rDqcdehHB-%(*L)?!0d(S*B~!0nFZk6TX?%V6q4FAJc8#!wy8`^mcWoD^C& zE#CC-564c>nFPiu;IAWWRbY?d2Xa_^d92r}EWpx2@FWLi2&7 zduwbgObE(zy%jCfg#LE#siAi9LMMB?hUh|M*d6VQ1LKNu%M#Fz#!>2yf$;XmLhI6Y zh7vBz<|HrTJc@rT$-unWEVVI~F)O`)M}>NCw;fCoe+giD#!Nvm#;u$g>2;UP9XrKKiPd&{p-=u*tDx$fiM^*2&nzqpB?{_oGH-r78C%bA&#wTz! zelJR zYAT4=t>ex_x&gs7N4}BIDFzx35}9mUU)Qcwpq{qwY^0!eziY{-T0q;h8H`{%b;|DJ zFWiW}YzDx~a>$N8DH*vd?Ihe^*Z$4BcW;>?(n(MWf)Hj0$-ZQ$wz?PWf3vnJ^?^=2 zxglEIsDdOV6j&bBt$$pjx4qjW?@R}KN;Z46deP+~)=v4Sb@$EI?7^E>p6t~Rr{AWt zH($lMoc>VjdsHq%(xpaS!^7k-6#j9$mi>E55GRO_y5@#Pl25lm!NL=amP3biDHn^d z`#rxUxFcMOL|8zH?F8SL{U_}%D#8*cl8)DzY=!|l;UoOm20B&elzZ6VU>X$9kEznG5$XGlfhN%&7?B-4?1b24wL z1D>pjj`O%;s&zC%@vKV9p8J#W#K=$0=R->MOqh(lg^aQv%P-}l|6B_KX^QMm4wUpq zRh&YzAMzea6cMSi}3{13-fxhDX!%m1_q;{hAV053r=+b?bFl9+$gPYxIU_Q>p>-fh=-~Z%D<@~vu8R=4Q*{3Tt7dz8yZn_Re6vy9hThws(0dAxuCveM( z^-Ie{tmX7JLBU=ea*Fx7cIaQbGkYpiJ~!R_=3`fInB7a@bqG&e-!JkYIOl+>ieSDw z$G`{j)t{b=BI|}XtS3e0-;w%}a$nrK@U%(e0^n%ZY}I^I-vMdv*{f@mUC^9awv-4jQeTfWX?;^mhfg_=X038 zeO2EDwFLjn943b#XM0%Lb~gF9iYB<}K1h@k>#8X6Q(PKCT(SJ{_PERB4==;fuzm15 zi7v6VxLz-U-7yQSj5$^Ji<@gh`6p4-Jz62f&KeRLduqltvkWL?Bh}_5T?pj-Y z74vC&ys~coxZp5AF_HG%4*xuJv6;K=xPwDJ7W<!z;_7B5}0 zy?`k;i%7J~F|o4w@Q)$H44_sLu04SV-%!Xm9o%`rOs6Yc@tHmyC+B{C51hLQDw-CR zi;ILL*U4}xP*UNq7BfP5EY!lP)FC$cC4FSFu^v$$T&9sjg{}eVZ>*N_NstI@1{saNM#zE#LB%nMK{y zG?@xPdTjncHVq*_n~4apV;oldJ+es~5d^va-9WKG>JsqOU`xJ#tuZod8C1t|XO2CF z^EC>uR<#=g$*v3x-=n8L17$L=s6O1e1Qxhad+pfHj0of!9E&VJ{2HT=3X_PCF6(rN zh3GhCC=6M8+a5kOj%O3m&fUbWYeAX$M=ybo^AlazE3fRT7ZhF7mq1jhTzQrNM3?LvY&_mFf%5x>7CKJ#{JY(cgVqciCREtV+~F_VFoAWZGhNk+ z=7PiJ0uZI60`zcpcTD-4a}U+D4AAGF&mWr_)OMay7V!E(g?=lp%PXBNAzzg$KninY z(HCmv<0s#i&8k=7e0w<&wMNVy>J$64PFiEmk%QSAI2uzKF3)%sbeExZWxLl@&1-9h z-~hwf%#Lo&s@>!82SGH2-{s#Y#39b5wtms6FnBLCg3zp9;o%`7!8`N3Q4#S)uW7K_ z!t81?-u>n}dY^M%@Ao;+56?O8_b*S5ql2}upsXMOK-kvC^2{$U z_znNTUplJ%mmvTLfg|1p=dT2aFhEiUVJaX(1w^TVST#Ua2MKVHqyZ?J;G!nDgaGMU zAX5uuYlAB%L7ooC*8$gbL6IIP(F3JOP>uvu`k)#GYEgiO2Dc5sT|>}d2rov%0B*-RfHE(^R?reJN~h-ht3`Dt2ST4d_WZ~M%^%U{3b>YKP#!ESa|W<+G9UyW8lz(lqqL@{)5ua<-5I2 zxciYITWTcw{P~6dX=z^#@Pp$Y1-qSh$Jxz&{u!nkFbrnaJ z*%~ZMa@|<$F1GSSo^0Vb^F2E+ckvU)Yf^*p`gCfuXsIKcd{}6IG14!^C8uS0 zqyCeXScX0tQBwl#Ylp>g8im>$YlSlOU-D89Y7IlfTp!lU9g632*+H|?-KPwT?H493r1uRc} zQOmDw!7;SV5_G=(Jy(JqJ0q9~$3kWF2W6@k3^cw%q9k`*x0D5)mrRNX6XSAKav!b5 z-ivcwuOAL(LUsOe(RLp#gdeNAB_T9vCmo|Mn$V;=cmKrvbFovjrmkpP3JPYp8aWY$ zyr_?{c(n$J^9iOo!>;x5FGvLN**QBtdtu%^=AgD&L=6klA_~5J%2lbs)3ev%`VGXx z*2AnyT&(1*NshhcAO14!Mm*h0eD+;Hp~QoK>D*@Fu}H4c#Tkgm;NBV|6z6qNZ-TTsqVn>%}CW zY=9&nJltLjK0)<*uvx>oB9<+#RHcxht05$BUe3w)<6{DmPH8endm%#yj4#s`Mx@51 zT_%pY@thwboXR}W?Y9oacIWyxZz4$UQXDB*T`jNBwW*s7G?JTfC3rXRh8f1@V{Y-g zVWMyBEM`c{DM z(hR0aYE?lVYHbga;8V6;Voi_PF^qi06gR28~8$eQ*s2@1Mq9VJ3Y_JVQdd$PIF#vwSW zPN3d57pZ4B)GJN-(qv{-+s?b+RaXgLK9C<$w`l3R%hD2M)8nUZIS82fyo~|K93eSbMjNK z-w`e>wgp;grpj*K(kz!)AWl;Ll;)K6&pK{-EH^zI7T4XLCF<8wj6AnfqNO%cDqu6> zw|(!NAbJ1U5f;`Zy?id=|~!HDYD$D}xYQzN1^!ZbuGd@ISMKZ{{tH y{?xPu?;ocnBq#n1*W03m_-V3=l&$xjWb;ky-bsXHaVDdG|0P?TgC)b Date: Sat, 2 Nov 2019 10:41:26 +0100 Subject: [PATCH 08/57] Add mapping from Xml to Core and acceptance tests --- NBi.Core/Api/Authentication/Anonymous.cs | 2 +- NBi.Core/Api/Authentication/ApiKey.cs | 2 +- NBi.Core/Api/Authentication/HttpBasic.cs | 2 +- .../Api/Authentication/NtlmCurrentUser.cs | 2 +- .../Api/Authentication/NtlmUserPassword.cs | 2 +- NBi.Core/Api/Authentication/OAuth2.cs | 2 +- NBi.Core/Api/Rest/HeaderRest.cs | 2 +- NBi.Core/Api/Rest/ParameterRest.cs | 2 +- NBi.Core/Api/Rest/RestEngine.cs | 5 +- NBi.Core/Api/Rest/SegmentRest.cs | 2 +- .../Hierarchical/Json/JsonPathRestEngine.cs | 31 ++++++++ NBi.Core/Hierarchical/Xml/XPathEngine.cs | 12 +++ NBi.Core/Hierarchical/Xml/XPathFileEngine.cs | 12 +-- NBi.Core/Hierarchical/Xml/XPathRestEngine.cs | 34 +++++++++ NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs | 3 + NBi.Core/NBi.Core.csproj | 2 + NBi.NUnit/Builder/Helper/RestHelper.cs | 76 +++++++++++++++++++ .../Helper/ResultSetResolverArgsBuilder.cs | 19 ++++- NBi.NUnit/NBi.NUnit.csproj | 1 + .../Positive/ResultSetConstraint.nbits | 31 ++++++++ NBi.Testing/NBi.Testing.csproj | 2 + .../NUnit/Builder/Helper/AnononymousXml.cs | 8 ++ .../NUnit/Builder/Helper/RestHelperTest.cs | 50 ++++++++++++ NBi.Xml/Items/Api/Rest/RestHeaderXml.cs | 2 +- NBi.Xml/Items/Api/Rest/RestParameterXml.cs | 2 +- NBi.Xml/Items/Api/Rest/RestPathXml.cs | 2 +- NBi.Xml/Items/Api/Rest/RestSegmentXml.cs | 2 +- .../Items/Hierarchical/Xml/XmlSourceXml.cs | 6 +- 28 files changed, 289 insertions(+), 29 deletions(-) create mode 100644 NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs create mode 100644 NBi.Core/Hierarchical/Xml/XPathRestEngine.cs create mode 100644 NBi.NUnit/Builder/Helper/RestHelper.cs create mode 100644 NBi.Testing/Unit/NUnit/Builder/Helper/AnononymousXml.cs create mode 100644 NBi.Testing/Unit/NUnit/Builder/Helper/RestHelperTest.cs diff --git a/NBi.Core/Api/Authentication/Anonymous.cs b/NBi.Core/Api/Authentication/Anonymous.cs index 1400fc129..6f038ef6d 100644 --- a/NBi.Core/Api/Authentication/Anonymous.cs +++ b/NBi.Core/Api/Authentication/Anonymous.cs @@ -7,7 +7,7 @@ namespace NBi.Core.Api.Authentication { - class Anonymous : IAuthentication + public class Anonymous : IAuthentication { public IAuthenticator GetAuthenticator() => null; } diff --git a/NBi.Core/Api/Authentication/ApiKey.cs b/NBi.Core/Api/Authentication/ApiKey.cs index 3861f7ad6..7979104af 100644 --- a/NBi.Core/Api/Authentication/ApiKey.cs +++ b/NBi.Core/Api/Authentication/ApiKey.cs @@ -9,7 +9,7 @@ namespace NBi.Core.Api.Authentication { - class ApiKey + public class ApiKey : IAuthentication { public IScalarResolver Name { get; } public IScalarResolver Value { get; } diff --git a/NBi.Core/Api/Authentication/HttpBasic.cs b/NBi.Core/Api/Authentication/HttpBasic.cs index c05afa11d..879203182 100644 --- a/NBi.Core/Api/Authentication/HttpBasic.cs +++ b/NBi.Core/Api/Authentication/HttpBasic.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Api.Authentication { - class HttpBasic : IAuthentication + public class HttpBasic : IAuthentication { public IScalarResolver Username { get; } public IScalarResolver Password { get; } diff --git a/NBi.Core/Api/Authentication/NtlmCurrentUser.cs b/NBi.Core/Api/Authentication/NtlmCurrentUser.cs index 966a5106b..8e82cfe41 100644 --- a/NBi.Core/Api/Authentication/NtlmCurrentUser.cs +++ b/NBi.Core/Api/Authentication/NtlmCurrentUser.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Api.Authentication { - class NtlmCurrentUser : IAuthentication + public class NtlmCurrentUser : IAuthentication { public NtlmCurrentUser() { } diff --git a/NBi.Core/Api/Authentication/NtlmUserPassword.cs b/NBi.Core/Api/Authentication/NtlmUserPassword.cs index 2b89fac5c..cb639f44d 100644 --- a/NBi.Core/Api/Authentication/NtlmUserPassword.cs +++ b/NBi.Core/Api/Authentication/NtlmUserPassword.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Api.Authentication { - class NtlmUserPassword : IAuthentication + public class NtlmUserPassword : IAuthentication { public IScalarResolver Username { get; } public IScalarResolver Password { get; } diff --git a/NBi.Core/Api/Authentication/OAuth2.cs b/NBi.Core/Api/Authentication/OAuth2.cs index fe56afbfa..2d64370c7 100644 --- a/NBi.Core/Api/Authentication/OAuth2.cs +++ b/NBi.Core/Api/Authentication/OAuth2.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Api.Authentication { - class OAuth2 : IAuthentication + public class OAuth2 : IAuthentication { public IScalarResolver AccessToken { get; } public IScalarResolver TokenType { get; } diff --git a/NBi.Core/Api/Rest/HeaderRest.cs b/NBi.Core/Api/Rest/HeaderRest.cs index 9df1b86a7..1478233d8 100644 --- a/NBi.Core/Api/Rest/HeaderRest.cs +++ b/NBi.Core/Api/Rest/HeaderRest.cs @@ -7,7 +7,7 @@ namespace NBi.Core.Api.Rest { - class HeaderRest + public class HeaderRest { public IScalarResolver Name { get; } public IScalarResolver Value { get; } diff --git a/NBi.Core/Api/Rest/ParameterRest.cs b/NBi.Core/Api/Rest/ParameterRest.cs index 8fb74c31a..15a570c5c 100644 --- a/NBi.Core/Api/Rest/ParameterRest.cs +++ b/NBi.Core/Api/Rest/ParameterRest.cs @@ -7,7 +7,7 @@ namespace NBi.Core.Api.Rest { - class ParameterRest + public class ParameterRest { public IScalarResolver Name { get; } public IScalarResolver Value { get; } diff --git a/NBi.Core/Api/Rest/RestEngine.cs b/NBi.Core/Api/Rest/RestEngine.cs index 7b62c9c27..1bd0ec94e 100644 --- a/NBi.Core/Api/Rest/RestEngine.cs +++ b/NBi.Core/Api/Rest/RestEngine.cs @@ -4,12 +4,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; namespace NBi.Core.Api.Rest { - class RestEngine + public class RestEngine { public IAuthentication Authentication { get; } public IScalarResolver BaseUrl { get; } @@ -23,6 +24,8 @@ public RestEngine(IAuthentication authentication, IScalarResolver baseUr public string Execute() { + ServicePointManager.SecurityProtocol = + SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; var baseUrl = BaseUrl.Execute(); var client = new RestClient(baseUrl) { diff --git a/NBi.Core/Api/Rest/SegmentRest.cs b/NBi.Core/Api/Rest/SegmentRest.cs index 86be18ce2..858293837 100644 --- a/NBi.Core/Api/Rest/SegmentRest.cs +++ b/NBi.Core/Api/Rest/SegmentRest.cs @@ -7,7 +7,7 @@ namespace NBi.Core.Api.Rest { - class SegmentRest + public class SegmentRest { public IScalarResolver Name { get; } public IScalarResolver Value { get; } diff --git a/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs new file mode 100644 index 000000000..86c5a1670 --- /dev/null +++ b/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs @@ -0,0 +1,31 @@ +using NBi.Core.Scalar.Resolver; +using NBi.Extensibility; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net; +using NBi.Core.Api.Rest; + +namespace NBi.Core.Hierarchical.Json +{ + public class JsonPathRestEngine : JsonPathEngine + { + public RestEngine Rest { get; } + + public JsonPathRestEngine(RestEngine rest, string from, IEnumerable selects) + : base(from, selects) + => (Rest) = (rest); + + public override IEnumerable Execute() + { + var jsonText = Rest.Execute(); + var json = JToken.Parse(jsonText); + return Execute(json); + } + } +} diff --git a/NBi.Core/Hierarchical/Xml/XPathEngine.cs b/NBi.Core/Hierarchical/Xml/XPathEngine.cs index 7095f74e6..9d47bee45 100644 --- a/NBi.Core/Hierarchical/Xml/XPathEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathEngine.cs @@ -76,5 +76,17 @@ protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceR ?? new XElement("null", "(null)") ).Value; } + + protected XmlReader CreateReader(string filePath, bool isRemoveDefaultNamespace) + { + var settings = new XmlReaderSettings(); + var streamReader = GetTextReader(filePath); + if (isRemoveDefaultNamespace) + return new XmlIgnoreNamespaceReader(streamReader, settings); + else + return XmlReader.Create(streamReader, settings); + } + + protected abstract TextReader GetTextReader(string filePath); } } diff --git a/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs b/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs index 3a30d51a2..3ffd7afe7 100644 --- a/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs @@ -39,17 +39,7 @@ protected virtual string EnsureFileExist() return filePath; } - private XmlReader CreateReader(string filePath, bool isRemoveDefaultNamespace) - { - var settings = new XmlReaderSettings(); - var streamReader = GetTextReader(filePath); - if (isRemoveDefaultNamespace) - return new XmlIgnoreNamespaceReader(streamReader, settings); - else - return XmlReader.Create(streamReader, settings); - } - - protected virtual TextReader GetTextReader(string filePath) + protected override TextReader GetTextReader(string filePath) => new StreamReader(filePath); } } diff --git a/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs b/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs new file mode 100644 index 000000000..b707ecf85 --- /dev/null +++ b/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs @@ -0,0 +1,34 @@ +using NBi.Core.Api.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace NBi.Core.Hierarchical.Xml +{ + public class XPathRestEngine : XPathEngine + { + public RestEngine Rest { get; } + + public XPathRestEngine(RestEngine rest, string from, IEnumerable selects, string defaultNamespacePrefix) + : base(from, selects, defaultNamespacePrefix, false) + => Rest = rest; + + public override IEnumerable Execute() + { + var xmlText = Rest.Execute(); + using (var xmlreader = CreateReader(xmlText, IsIgnoreNamespace)) + { + var doc = XDocument.Load(xmlreader); + return Execute(doc); + } + } + + protected override TextReader GetTextReader(string text) + => new StringReader(text); + } +} diff --git a/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs b/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs index 3db3a97c3..0b99a639f 100644 --- a/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs +++ b/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs @@ -22,5 +22,8 @@ public override IEnumerable Execute() var doc = XDocument.Load(Url); return Execute(doc); } + + protected override TextReader GetTextReader(string filePath) + => throw new NotImplementedException(); } } diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 69c4ec5c5..70137ebcb 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -265,8 +265,10 @@ + + diff --git a/NBi.NUnit/Builder/Helper/RestHelper.cs b/NBi.NUnit/Builder/Helper/RestHelper.cs new file mode 100644 index 000000000..57591bf6c --- /dev/null +++ b/NBi.NUnit/Builder/Helper/RestHelper.cs @@ -0,0 +1,76 @@ +using NBi.Core.Injection; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core.Api.Rest; +using NBi.Xml.Items.Api.Rest; +using NBi.Core.Api.Authentication; +using NBi.Xml.Items.Api.Authentication; +using NBi.Xml.Settings; + +namespace NBi.NUnit.Builder.Helper +{ + public class RestHelper + { + private ServiceLocator ServiceLocator { get; } + private IDictionary Variables { get; } + private SettingsXml Settings { get; } = SettingsXml.Empty; + private SettingsXml.DefaultScope Scope { get; } = SettingsXml.DefaultScope.Everywhere; + + public RestHelper(ServiceLocator serviceLocator, SettingsXml settings, SettingsXml.DefaultScope scope, IDictionary variables) + => (ServiceLocator, Settings, Scope, Variables) = (serviceLocator, settings ?? SettingsXml.Empty, scope, variables ?? new Dictionary()); + + public RestEngine Execute(object rest) + { + switch (rest) + { + case RestXml x: return BuildRestEngine(x); + default: throw new ArgumentOutOfRangeException(); + } + } + + private RestEngine BuildRestEngine(RestXml restXml) + { + var helper = new ScalarHelper(ServiceLocator, Settings, Scope, new Context(Variables)); + + var authentication = BuildRestAuthentication(restXml.Authentication); + var resolverUrl = helper.InstantiateResolver(restXml.BaseAddress); + var resolverPath = helper.InstantiateResolver(restXml.Path.Value); + + var parameters = restXml.Parameters.Select(x => new ParameterRest( + helper.InstantiateResolver(x.Name) + , helper.InstantiateResolver(x.Value) + )); + + var segments = restXml.Segments.Select(x => new SegmentRest( + helper.InstantiateResolver(x.Name) + , helper.InstantiateResolver(x.Value) + )); + + var headers = restXml.Headers.Select(x => new HeaderRest( + helper.InstantiateResolver(x.Name) + , helper.InstantiateResolver(x.Value) + )); + + return new RestEngine(authentication, resolverUrl, resolverPath, parameters, segments, headers); + } + + private IAuthentication BuildRestAuthentication(AuthenticationXml authentication) + { + var helper = new ScalarHelper(ServiceLocator, Settings, Scope, new Context(Variables)); + switch (authentication.Protocol) + { + case AnonymousXml _: return new Anonymous(); + case ApiKeyXml x: return new ApiKey(helper.InstantiateResolver(x.Name), helper.InstantiateResolver(x.Value)); + case HttpBasicXml x: return new HttpBasic(helper.InstantiateResolver(x.Username), helper.InstantiateResolver(x.Password)); + case NtmlCurrentUserXml _: return new NtlmCurrentUser(); + case NtmlUserPasswordXml x: return new NtlmUserPassword(helper.InstantiateResolver(x.Username), helper.InstantiateResolver(x.Password)); + case OAuth2Xml x: return new OAuth2(helper.InstantiateResolver(x.AccessToken), helper.InstantiateResolver(x.TokenType)); + default: throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 9dc64b1cd..ff04fd9da 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -21,6 +21,10 @@ using System.Threading.Tasks; using NBi.Xml.Items.Hierarchical.Json; using NBi.Core.Hierarchical.Json; +using NBi.Core.Api.Rest; +using NBi.Core.Api.Authentication; +using NBi.Xml.Items.Api.Rest; +using NBi.Xml.Items.Api.Authentication; namespace NBi.NUnit.Builder.Helper { @@ -130,7 +134,7 @@ private ResultSetResolverArgs BuildSequenceCombinationResolverArgs(SequenceCombi private ResultSetResolverArgs BuildSequenceResolverArgs(SequenceXml sequenceXml) { - + var sequenceFactory = new SequenceResolverFactory(ServiceLocator); var builder = new SequenceResolverArgsBuilder(ServiceLocator); builder.Setup(settings); @@ -195,7 +199,7 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) selects.Add(selectFactory.Instantiate(select.Value, select.Attribute, select.Evaluate)); var helper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); - + XPathEngine engine = null; if (xmlSource.File != null) @@ -205,7 +209,11 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) } else if (xmlSource.Url != null) engine = new XPathUrlEngine(xmlSource.Url.Value, xmlSource.XPath.From.Value, selects, xmlSource.XPath?.DefaultNamespacePrefix); - + else if (xmlSource.Rest != null) + { + var restHelper = new RestHelper(ServiceLocator, settings, scope, Variables); + engine = new XPathRestEngine(restHelper.Execute(xmlSource.Rest), xmlSource.XPath.From.Value, selects, xmlSource.XPath?.DefaultNamespacePrefix); + } return new XPathResultSetResolverArgs(engine); } @@ -232,6 +240,11 @@ private ResultSetResolverArgs BuildJsonPathResolverArgs(JsonSourceXml jsonSource var resolverUrl = helper.InstantiateResolver(jsonSource.Url.Value); engine = new JsonPathUrlEngine(resolverUrl, jsonSource.JsonPath.From.Value, selects); } + else if (jsonSource.Rest != null) + { + var restHelper = new RestHelper(ServiceLocator, settings, scope, Variables); + engine = new JsonPathRestEngine(restHelper.Execute(jsonSource.Rest), jsonSource.JsonPath.From.Value, selects); + } return new XPathResultSetResolverArgs(engine); } diff --git a/NBi.NUnit/NBi.NUnit.csproj b/NBi.NUnit/NBi.NUnit.csproj index cd7c53db9..ee4cb991e 100644 --- a/NBi.NUnit/NBi.NUnit.csproj +++ b/NBi.NUnit/NBi.NUnit.csproj @@ -79,6 +79,7 @@ + diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index ac36516ec..426962874 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -635,6 +635,37 @@ + + + + + + entries + animals + + + $.entries[*] + + + + + + + + + + + Cat Facts + no + + + RandomCat + yes + + + + + diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 0495b5af1..34f70d249 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -201,9 +201,11 @@ + + diff --git a/NBi.Testing/Unit/NUnit/Builder/Helper/AnononymousXml.cs b/NBi.Testing/Unit/NUnit/Builder/Helper/AnononymousXml.cs new file mode 100644 index 000000000..5bf83680e --- /dev/null +++ b/NBi.Testing/Unit/NUnit/Builder/Helper/AnononymousXml.cs @@ -0,0 +1,8 @@ +using NBi.Xml.Items.Api.Authentication; + +namespace NBi.Testing.Unit.NUnit.Builder.Helper +{ + internal class AnononymousXml : BaseAuthenticationXml + { + } +} \ No newline at end of file diff --git a/NBi.Testing/Unit/NUnit/Builder/Helper/RestHelperTest.cs b/NBi.Testing/Unit/NUnit/Builder/Helper/RestHelperTest.cs new file mode 100644 index 000000000..631e042c1 --- /dev/null +++ b/NBi.Testing/Unit/NUnit/Builder/Helper/RestHelperTest.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core.Injection; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; +using NBi.NUnit.Builder.Helper; +using NBi.Xml.Items.Api.Authentication; +using NBi.Xml.Items.Api.Rest; +using NBi.Xml.Settings; +using NUnit.Framework; + +namespace NBi.Testing.Unit.NUnit.Builder.Helper +{ + public class RestHelperTest + { + [Test] + public void Execute_RestXml_CorrectInterpretation() + { + var xml = new RestXml() + { + Authentication = new AuthenticationXml { Protocol = new AnonymousXml() }, + BaseAddress = "https://api.website.com", + Path= new RestPathXml { Value = "v1/user/{user}" }, + Headers = new List { new RestHeaderXml { Name = "user-agent", Value="nbi"} }, + Parameters = new List { new RestParameterXml { Name = "order-by", Value = "FullName | text-to-lower" } }, + Segments = new List { new RestSegmentXml { Name = "user", Value = "@User" } }, + }; + + var variables = new Dictionary { { "User", new GlobalVariable(new LiteralScalarResolver("seddryck")) } }; + + var helper = new RestHelper(new ServiceLocator(), null, SettingsXml.DefaultScope.Everywhere , variables); + var restEngine = helper.Execute(xml); + Assert.That(restEngine.BaseUrl.Execute(), Is.EqualTo("https://api.website.com")); + Assert.That(restEngine.Path.Execute(), Is.EqualTo("v1/user/{user}")); + Assert.That(restEngine.Headers.Count, Is.EqualTo(1)); + Assert.That(restEngine.Headers.First().Name.Execute(), Is.EqualTo("user-agent")); + Assert.That(restEngine.Headers.First().Value.Execute(), Is.EqualTo("nbi")); + Assert.That(restEngine.Parameters.Count, Is.EqualTo(1)); + Assert.That(restEngine.Parameters.First().Name.Execute(), Is.EqualTo("order-by")); + Assert.That(restEngine.Parameters.First().Value.Execute(), Is.EqualTo("fullname")); + Assert.That(restEngine.Segments.Count, Is.EqualTo(1)); + Assert.That(restEngine.Segments.First().Name.Execute(), Is.EqualTo("user")); + Assert.That(restEngine.Segments.First().Value.Execute(), Is.EqualTo("seddryck")); + } + + } +} diff --git a/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs b/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs index 72ac42645..ead098e90 100644 --- a/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs +++ b/NBi.Xml/Items/Api/Rest/RestHeaderXml.cs @@ -4,7 +4,7 @@ using System.Xml.Serialization; using NBi.Core.Query; -namespace NBi.Xml.Items +namespace NBi.Xml.Items.Api.Rest { public class RestHeaderXml { diff --git a/NBi.Xml/Items/Api/Rest/RestParameterXml.cs b/NBi.Xml/Items/Api/Rest/RestParameterXml.cs index 0b2bc698f..f4c829c5e 100644 --- a/NBi.Xml/Items/Api/Rest/RestParameterXml.cs +++ b/NBi.Xml/Items/Api/Rest/RestParameterXml.cs @@ -4,7 +4,7 @@ using System.Xml.Serialization; using NBi.Core.Query; -namespace NBi.Xml.Items +namespace NBi.Xml.Items.Api.Rest { public class RestParameterXml { diff --git a/NBi.Xml/Items/Api/Rest/RestPathXml.cs b/NBi.Xml/Items/Api/Rest/RestPathXml.cs index 49e154890..b0f85a221 100644 --- a/NBi.Xml/Items/Api/Rest/RestPathXml.cs +++ b/NBi.Xml/Items/Api/Rest/RestPathXml.cs @@ -4,7 +4,7 @@ using System.Xml.Serialization; using NBi.Core.Query; -namespace NBi.Xml.Items +namespace NBi.Xml.Items.Api.Rest { public class RestPathXml { diff --git a/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs b/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs index 7f30eaecc..6b5ea70fa 100644 --- a/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs +++ b/NBi.Xml/Items/Api/Rest/RestSegmentXml.cs @@ -4,7 +4,7 @@ using System.Xml.Serialization; using NBi.Core.Query; -namespace NBi.Xml.Items +namespace NBi.Xml.Items.Api.Rest { public class RestSegmentXml { diff --git a/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs b/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs index 32e66e5f5..56794214a 100644 --- a/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs +++ b/NBi.Xml/Items/Hierarchical/Xml/XmlSourceXml.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Xml.Items.Api.Rest; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -20,6 +21,9 @@ public class XmlSourceXml : BaseItem [XmlElement("url")] public UrlXml Url { get; set; } + [XmlElement("rest")] + public RestXml Rest { get; set; } + [XmlElement("xpath")] public XPathXml XPath { get; set; } } From 3367fba05c1285a47d9ceb5374edb8ed9495f526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 2 Nov 2019 11:12:49 +0100 Subject: [PATCH 09/57] Fix issue when Nuget version is lower than 5.3 --- .../NBi.Extensibility.nuspec | 1 + .../NBi.Framework.Tools.nuspec | 1 + .packages/NBi.Framework/NBi.Framework.nuspec | 1 + .packages/package-NBi.ps1 | 34 ++++++++++++++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec index a4fd7076e..285f910c6 100644 --- a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec +++ b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec @@ -8,6 +8,7 @@ Apache-2.0 https://github.com/Seddryck/NBi images\logo-2x.png + https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png false Extensibility points of NBi. This package contains the interfaces to implement to extend NBi features. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. diff --git a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec index 16e4bbce5..37bf6697a 100644 --- a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec +++ b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec @@ -8,6 +8,7 @@ Apache-2.0 https://github.com/Seddryck/NBi images\logo-2x.png + https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png false This package contains the NBi framework and copy it to the tools folder. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. diff --git a/.packages/NBi.Framework/NBi.Framework.nuspec b/.packages/NBi.Framework/NBi.Framework.nuspec index ff7da9619..fe5e4408b 100644 --- a/.packages/NBi.Framework/NBi.Framework.nuspec +++ b/.packages/NBi.Framework/NBi.Framework.nuspec @@ -8,6 +8,7 @@ Apache-2.0 https://github.com/Seddryck/NBi images\logo-2x.png + https://raw.githubusercontent.com/Seddryck/nbi/gh-pages/img/logo-2x.png false This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. This package contains the NBi framework and references each dll to your project. This package is not intended to be directly used by end-users willing to create test-suites. Check the package NBi.VisualStudio, if you want to facilitate the usage of NBi from Visual Studio. NBi is a testing framework (add-on to NUnit) for Business Intelligence and Data Quality. It supports the Microsoft Data platform (SQL Server Database engine, SSIS, SSAS, SSRS) but also MySQL, PostgreSQL and other NoSQL solutions. diff --git a/.packages/package-NBi.ps1 b/.packages/package-NBi.ps1 index 086503666..03256253c 100644 --- a/.packages/package-NBi.ps1 +++ b/.packages/package-NBi.ps1 @@ -33,6 +33,17 @@ $depList = $dependencies.Values -join [Environment]::NewLine + "`t`t" $thisYear = get-date -Format yyyy Write-Host "Setting copyright until $thisYear" +$nugetVersion = nuget help | select -First 1 +Write-Host "Nuget's version: $nugetVersion" +if ($nugetVersion -lt '5.3') +{ + $xpath = ('/package/metadata/icon') +} +else +{ + $xpath = ('/package/metadata/iconUrl') +} + #For NBi.Framework (dll) Write-Host "Packaging NBi.Framework" $lib = "$root\NBi.Framework\lib\net461\" @@ -47,14 +58,17 @@ Copy-Item $root\..\NBi.Testing\bin\Debug\NBi.Testing.dll $lib Write-Host "Setting .nuspec version tag to $version" - - $content = (Get-Content $root\NBi.Framework\NBi.Framework.nuspec -Encoding UTF8) $content = $content -replace '\$version\$',$version $content = $content -replace '\$thisYear\$',$thisYear $content = $content -replace '\$depList\$',$depList -$content | Out-File $root\NBi.Framework\NBi.Framework.compiled.nuspec -Encoding UTF8 +$xml = New-Object -TypeName System.Xml.XmlDocument +$xml.LoadXml($content) +$iconNode = $xml.SelectSingleNode($xpath) +$iconNode.ParentNode.RemoveChild($iconNode) + +$xml.OuterXml | Out-File $root\NBi.Framework\NBi.Framework.compiled.nuspec -Encoding UTF8 & NuGet.exe pack $root\..\.packages\NBi.Framework\NBi.Framework.compiled.nuspec -Version $version -OutputDirectory $root\..\.nupkg Write-Host "Package for NBi.Framework is ready" @@ -77,7 +91,12 @@ $content = $content -replace '\$version\$',$version $content = $content -replace '\$thisYear\$',$thisYear $content = $content -replace '\$depList\$',$depList -$content | Out-File $root\NBi.Framework.Tools\NBi.Framework.Tools.compiled.nuspec -Encoding UTF8 +$xml = New-Object -TypeName System.Xml.XmlDocument +$xml.LoadXml($content) +$iconNode = $xml.SelectSingleNode($xpath) +$iconNode.ParentNode.RemoveChild($iconNode) + +$xml.OuterXml | Out-File $root\NBi.Framework.Tools\NBi.Framework.Tools.compiled.nuspec -Encoding UTF8 & NuGet.exe pack $root\..\.packages\NBi.Framework.Tools\NBi.Framework.Tools.compiled.nuspec -Version $version -OutputDirectory $root\..\.nupkg Write-Host "Package for NBi.Framework.Tools is ready" @@ -99,7 +118,12 @@ $content = (Get-Content $root\NBi.Extensibility\NBi.Extensibility.nuspec -Encodi $content = $content -replace '\$version\$',$version $content = $content -replace '\$thisYear\$',$thisYear -$content | Out-File $root\NBi.Extensibility\NBi.Extensibility.compiled.nuspec -Encoding UTF8 +$xml = New-Object -TypeName System.Xml.XmlDocument +$xml.LoadXml($content) +$iconNode = $xml.SelectSingleNode($xpath) +$iconNode.ParentNode.RemoveChild($iconNode) + +$xml.OuterXml | Out-File $root\NBi.Extensibility\NBi.Extensibility.compiled.nuspec -Encoding UTF8 & NuGet.exe pack $root\..\.packages\NBi.Extensibility\NBi.Extensibility.compiled.nuspec -Version $version -OutputDirectory $root\..\.nupkg Write-Host "Package for NBi.Extensibility is ready" \ No newline at end of file From e817cb2682d1ee607dee82576f2b39eff0af9bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 2 Nov 2019 22:42:55 +0100 Subject: [PATCH 10/57] Fix issue when reading nuget version --- .packages/package-NBi.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.packages/package-NBi.ps1 b/.packages/package-NBi.ps1 index 03256253c..b224e226e 100644 --- a/.packages/package-NBi.ps1 +++ b/.packages/package-NBi.ps1 @@ -33,7 +33,7 @@ $depList = $dependencies.Values -join [Environment]::NewLine + "`t`t" $thisYear = get-date -Format yyyy Write-Host "Setting copyright until $thisYear" -$nugetVersion = nuget help | select -First 1 +$nugetVersion = (((nuget help | select -First 1).Split(':')) | select -Last 1).Trim() Write-Host "Nuget's version: $nugetVersion" if ($nugetVersion -lt '5.3') { @@ -73,6 +73,7 @@ $xml.OuterXml | Out-File $root\NBi.Framework\NBi.Framework.compiled.nuspec -Enco & NuGet.exe pack $root\..\.packages\NBi.Framework\NBi.Framework.compiled.nuspec -Version $version -OutputDirectory $root\..\.nupkg Write-Host "Package for NBi.Framework is ready" + #For NBi.Framework.Tools Write-Host "Packaging NBi.Framework.Tools" $lib = "$root\NBi.Framework.Tools\tools\" From 4d396e3df68d43e8eaa1d8ab2acf04c37980cf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 2 Nov 2019 22:58:08 +0100 Subject: [PATCH 11/57] Remove minClientVersion --- .packages/NBi.Extensibility/NBi.Extensibility.nuspec | 2 +- .packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec | 2 +- .packages/NBi.Framework/NBi.Framework.nuspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec index 285f910c6..98944143f 100644 --- a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec +++ b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec @@ -1,6 +1,6 @@ - + NBi.Extensibility $version$ Seddryck diff --git a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec index 37bf6697a..5aa7e07dd 100644 --- a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec +++ b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec @@ -1,6 +1,6 @@ - + NBi.Framework.Tools $version$ Seddryck diff --git a/.packages/NBi.Framework/NBi.Framework.nuspec b/.packages/NBi.Framework/NBi.Framework.nuspec index fe5e4408b..fe4bbc056 100644 --- a/.packages/NBi.Framework/NBi.Framework.nuspec +++ b/.packages/NBi.Framework/NBi.Framework.nuspec @@ -1,6 +1,6 @@ - + NBi.Framework $version$ Seddryck From 16222d9fcf24635ab84a77f82338ee0e0578cd9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 3 Nov 2019 14:37:32 +0100 Subject: [PATCH 12/57] Update Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 7bc9c24a7..5297b2a6f 100644 --- a/Readme.md +++ b/Readme.md @@ -17,7 +17,7 @@ The main goal of this framework is to let users create tests with a declarative **Dev. activity:** [![GitHub last commit](https://img.shields.io/github/last-commit/Seddryck/nbi.svg)](https://github.com/Seddryck/NBi/releases/latest) ![Still maintained](https://img.shields.io/maintenance/yes/2019.svg) -![GitHub commits since tagged version](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.20/develop) +![GitHub commits since tagged version](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop) ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/Seddryck/NBi) **Continuous integration builds:** [![Build status](https://ci.appveyor.com/api/projects/status/t5m0hr57vnsdv0v7?svg=true)](https://ci.appveyor.com/project/Seddryck/nbi) From 63d87b998b4a60c1f1d368f91eaff367e7cfedd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 3 Nov 2019 14:38:38 +0100 Subject: [PATCH 13/57] Update Readme.md --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index 5297b2a6f..8df6bb8e6 100644 --- a/Readme.md +++ b/Readme.md @@ -18,6 +18,7 @@ The main goal of this framework is to let users create tests with a declarative **Dev. activity:** [![GitHub last commit](https://img.shields.io/github/last-commit/Seddryck/nbi.svg)](https://github.com/Seddryck/NBi/releases/latest) ![Still maintained](https://img.shields.io/maintenance/yes/2019.svg) ![GitHub commits since tagged version](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop) +![GitHub commits on v2.0](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop_v2) ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/Seddryck/NBi) **Continuous integration builds:** [![Build status](https://ci.appveyor.com/api/projects/status/t5m0hr57vnsdv0v7?svg=true)](https://ci.appveyor.com/project/Seddryck/nbi) From 0ada10ad6ace648ca6eb9eed7e349b9fd70afadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 3 Nov 2019 14:40:15 +0100 Subject: [PATCH 14/57] Update Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 8df6bb8e6..c2c0bb9d9 100644 --- a/Readme.md +++ b/Readme.md @@ -18,7 +18,7 @@ The main goal of this framework is to let users create tests with a declarative **Dev. activity:** [![GitHub last commit](https://img.shields.io/github/last-commit/Seddryck/nbi.svg)](https://github.com/Seddryck/NBi/releases/latest) ![Still maintained](https://img.shields.io/maintenance/yes/2019.svg) ![GitHub commits since tagged version](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop) -![GitHub commits on v2.0](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop_v2) +![GitHub commits on v2.0](https://img.shields.io/github/commits-since/seddryck/nbi/v1.21/develop_v2?label=commits%20on%20v2.0) ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/Seddryck/NBi) **Continuous integration builds:** [![Build status](https://ci.appveyor.com/api/projects/status/t5m0hr57vnsdv0v7?svg=true)](https://ci.appveyor.com/project/Seddryck/nbi) From ea0e7ad8c0390bbb10a869957fb7bca0026c31eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 4 Nov 2019 20:47:53 +0100 Subject: [PATCH 15/57] Implementation of custom-scalar and applicable to variable --- .../{Decoration => }/AbstractCustomFactory.cs | 6 +- .../{Decoration => }/ICustomArgs.cs | 2 +- NBi.Core/NBi.Core.csproj | 6 +- .../Scalar/Resolver/CustomScalarResolver.cs | 31 ++++++++++ .../Resolver/CustomScalarResolverArgs.cs | 25 +++++++++ .../Scalar/Resolver/ScalarResolverFactory.cs | 2 + NBi.NUnit.Runtime/TestSuite.cs | 2 + .../Helper/ScalarResolverArgsBuilder.cs | 10 ++++ NBi.Testing.Core/NBi.Testing.Core.csproj | 4 ++ .../Resolver/CustomScalarResolverTest.cs | 56 +++++++++++++++++++ .../Resolver/Resources/MyCustomClass.cs | 14 +++++ .../Resources/MyCustomClassWithParams.cs | 20 +++++++ .../Variables/GlobalVariableXmlTest.cs | 42 ++++++++++++++ .../Resources/CustomVariableDaysBetween.cs | 20 +++++++ .../Resources/Positive/Variable.nbits | 28 ++++++++++ NBi.Testing/NBi.Testing.csproj | 1 + NBi.Xml/NBi.Xml.csproj | 2 + NBi.Xml/Schema/BaseType.xsd | 27 +++------ .../Custom/CustomScalarParameterXml.cs | 18 ++++++ NBi.Xml/Variables/Custom/CustomScalarXml.cs | 21 +++++++ NBi.Xml/Variables/GlobalVariableXml.cs | 3 + NBi.sln | 1 + 22 files changed, 315 insertions(+), 26 deletions(-) rename NBi.Core/Assemblies/{Decoration => }/AbstractCustomFactory.cs (94%) rename NBi.Core/Assemblies/{Decoration => }/ICustomArgs.cs (90%) create mode 100644 NBi.Core/Scalar/Resolver/CustomScalarResolver.cs create mode 100644 NBi.Core/Scalar/Resolver/CustomScalarResolverArgs.cs create mode 100644 NBi.Testing.Core/Scalar/Resolver/CustomScalarResolverTest.cs create mode 100644 NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClass.cs create mode 100644 NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClassWithParams.cs create mode 100644 NBi.Testing/Acceptance/Resources/CustomVariableDaysBetween.cs create mode 100644 NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs create mode 100644 NBi.Xml/Variables/Custom/CustomScalarXml.cs diff --git a/NBi.Core/Assemblies/Decoration/AbstractCustomFactory.cs b/NBi.Core/Assemblies/AbstractCustomFactory.cs similarity index 94% rename from NBi.Core/Assemblies/Decoration/AbstractCustomFactory.cs rename to NBi.Core/Assemblies/AbstractCustomFactory.cs index db95d77c8..4d691eda2 100644 --- a/NBi.Core/Assemblies/Decoration/AbstractCustomFactory.cs +++ b/NBi.Core/Assemblies/AbstractCustomFactory.cs @@ -9,7 +9,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Assemblies.Decoration +namespace NBi.Core.Assemblies { public class AbstractCustomFactory where T:class { @@ -28,7 +28,7 @@ protected T Instantiate(ICustomArgs args) catch (TypeNotExistingException) { throw new NBiException($"The assembly '{assembly.FullName}' doesn't contain any type named '{args.TypeName}'. This type was describe in the test as a {CustomKind}."); } catch (TypeNotImplementingInterfaceException) - { throw new NBiException($"The type '{typeName}' of the assembly '{assembly.FullName}' is not implementing the interface '{typeof(ICustomCommand).Name}' but is used as a {CustomKind}."); } + { throw new NBiException($"The type '{typeName}' of the assembly '{assembly.FullName}' is not implementing the interface '{typeof(T).Name}' but is used as a {CustomKind}."); } catch (NoConstructorFoundException) { throw new NBiException($"The type '{typeName}' of the assembly '{assembly.FullName}' has no constructor matching with the {parameters.Count()} parameter{(parameters.Count() > 1 ? "s" : string.Empty)} that {(parameters.Count() > 1 ? "were" : "was")} provided."); } } @@ -60,7 +60,7 @@ protected internal Type GetType(Assembly assembly, string typeName) } protected internal IReadOnlyDictionary GetParameters(IReadOnlyDictionary parameters) - => parameters?.Select(x => new KeyValuePair(x.Key, x.Value.Execute())) + => parameters?.Select(x => new { x.Key, Value = x.Value.Execute() }) .ToDictionary(x => x.Key, y => y.Value); protected internal T Instantiate(Type customCommandType, IReadOnlyDictionary parameters) diff --git a/NBi.Core/Assemblies/Decoration/ICustomArgs.cs b/NBi.Core/Assemblies/ICustomArgs.cs similarity index 90% rename from NBi.Core/Assemblies/Decoration/ICustomArgs.cs rename to NBi.Core/Assemblies/ICustomArgs.cs index 56fc8e064..977a196c9 100644 --- a/NBi.Core/Assemblies/Decoration/ICustomArgs.cs +++ b/NBi.Core/Assemblies/ICustomArgs.cs @@ -6,7 +6,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Assemblies.Decoration +namespace NBi.Core.Assemblies { public interface ICustomArgs { diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 70137ebcb..ef3a790fe 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -134,13 +134,13 @@ - + - + @@ -671,6 +671,8 @@ + + diff --git a/NBi.Core/Scalar/Resolver/CustomScalarResolver.cs b/NBi.Core/Scalar/Resolver/CustomScalarResolver.cs new file mode 100644 index 000000000..b55aea2ae --- /dev/null +++ b/NBi.Core/Scalar/Resolver/CustomScalarResolver.cs @@ -0,0 +1,31 @@ +using Microsoft.CSharp; +using NBi.Core.Assemblies; +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Scalar.Resolver +{ + class CustomScalarResolver : AbstractCustomFactory, IScalarResolver + { + private CustomScalarResolverArgs Args {get;} + + public CustomScalarResolver(CustomScalarResolverArgs args) + => Args = args; + + protected override string CustomKind => "custom evaluation of a scalar"; + + public T Execute() + { + var instance = Instantiate(Args); + var value = instance.Execute(); + return (T)Convert.ChangeType(value, typeof(T)); + } + + object IResolver.Execute() => Execute(); + } +} \ No newline at end of file diff --git a/NBi.Core/Scalar/Resolver/CustomScalarResolverArgs.cs b/NBi.Core/Scalar/Resolver/CustomScalarResolverArgs.cs new file mode 100644 index 000000000..e4abb8cd5 --- /dev/null +++ b/NBi.Core/Scalar/Resolver/CustomScalarResolverArgs.cs @@ -0,0 +1,25 @@ +using NBi.Core.Assemblies; +using NBi.Core.Query; +using NBi.Core.Query.Resolver; +using NBi.Core.ResultSet.Resolver; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Scalar.Resolver +{ + public class CustomScalarResolverArgs : IScalarResolverArgs, ICustomArgs + { + public IScalarResolver AssemblyPath { get; } + + public IScalarResolver TypeName { get; } + + public IReadOnlyDictionary Parameters { get; } + + public CustomScalarResolverArgs(IScalarResolver assemblyPath, IScalarResolver typeName, IDictionary parameters) + => (AssemblyPath, TypeName, Parameters) = (assemblyPath, typeName, new ReadOnlyDictionary(parameters)); + } +} diff --git a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs index b109beb41..5bfd1d117 100644 --- a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs +++ b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs @@ -56,6 +56,8 @@ public IScalarResolver Instantiate(IScalarResolverArgs args) return new NCalcScalarResolver(x); case EnvironmentScalarResolverArgs x: return new EnvironmentScalarResolver(x); + case CustomScalarResolverArgs x: + return new CustomScalarResolver(x); case FormatScalarResolverArgs x: return typeof(T) == typeof(string) ? (IScalarResolver)new FormatScalarResolver(x, serviceLocator) : throw new ArgumentException("You cannot instantiate a FormatScalarResolver that is not a string."); case FunctionScalarResolverArgs x: diff --git a/NBi.NUnit.Runtime/TestSuite.cs b/NBi.NUnit.Runtime/TestSuite.cs index 1db1200a9..8ef9f3cc9 100644 --- a/NBi.NUnit.Runtime/TestSuite.cs +++ b/NBi.NUnit.Runtime/TestSuite.cs @@ -302,6 +302,8 @@ private IDictionary BuildVariables(IEnumerable(obj.AssemblyPath), + helper.InstantiateResolver(obj.TypeName), + obj.Parameters.Select(x => new { x.Name, ScalarResolver = (IScalarResolver)helper.InstantiateResolver(x.StringValue)}) + .ToDictionary(x => x.Name, y => y.ScalarResolver) + ); + break; default: var factory = new ScalarResolverArgsFactory(ServiceLocator, Context); args = factory.Instantiate(obj as string); diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 496929a58..b56ac013a 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -260,6 +260,9 @@ + + + @@ -328,6 +331,7 @@ + diff --git a/NBi.Testing.Core/Scalar/Resolver/CustomScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/CustomScalarResolverTest.cs new file mode 100644 index 000000000..d1cbb767e --- /dev/null +++ b/NBi.Testing.Core/Scalar/Resolver/CustomScalarResolverTest.cs @@ -0,0 +1,56 @@ +using Moq; +using NBi.Core.Scalar.Resolver; +using NBi.Testing.Core.Scalar.Resolver.Resources; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Scalar.Resolver +{ + public class CustomScalarResolverTest + { + [Test] + public void Execute_TypeWithoutParam_CorrectEvaluation() + { + var args = new CustomScalarResolverArgs + ( + new LiteralScalarResolver(GetType().Assembly.Location), + new LiteralScalarResolver($"{typeof(MyCustomClass).Namespace}.{typeof(MyCustomClass).Name}"), + new Dictionary() + ); + var resolver = new CustomScalarResolver(args); + Assert.That(resolver.Execute(), Is.EqualTo("myValue")); + } + + [Test] + public void Execute_TypeWithParam_CorrectEvaluation() + { + var args = new CustomScalarResolverArgs + ( + new LiteralScalarResolver(GetType().Assembly.Location), + new LiteralScalarResolver($"{typeof(MyCustomClassWithParams).Namespace}.{typeof(MyCustomClassWithParams).Name}"), + new Dictionary() { { "foo", new LiteralScalarResolver(5) }, { "bar", new LiteralScalarResolver(new DateTime(2019, 1, 1)) } } + ); + var resolver = new CustomScalarResolver(args); + var output = resolver.Execute(); + Assert.That(output, Is.EqualTo(new DateTime(2019,1,6))); + } + + //[Test] + //public void Execute_TwoCalls_OneExecution() + //{ + // var factory = new CustomScalarFactory(); + // var mock = new Mock(); + // mock.SetupSequence(x => x.Execute()).Returns(true).Returns(false); + + // var customEvaluation = factory.Instantiate(mock.Object); + // Assert.That(customEvaluation.Execute(), Is.True); + // Assert.That(customEvaluation.Execute(), Is.True); + // mock.Verify(x => x.Execute(), Times.Once); + //} + } +} diff --git a/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClass.cs b/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClass.cs new file mode 100644 index 000000000..543b9b147 --- /dev/null +++ b/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClass.cs @@ -0,0 +1,14 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Scalar.Resolver.Resources +{ + public class MyCustomClass : IScalarResolver + { + public object Execute() => "myValue"; + } +} diff --git a/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClassWithParams.cs b/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClassWithParams.cs new file mode 100644 index 000000000..86288361b --- /dev/null +++ b/NBi.Testing.Core/Scalar/Resolver/Resources/MyCustomClassWithParams.cs @@ -0,0 +1,20 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Scalar.Resolver.Resources +{ + public class MyCustomClassWithParams : IScalarResolver + { + private int Foo { get; } + private DateTime Bar { get; } + + public MyCustomClassWithParams(DateTime bar, int foo) + => (Bar, Foo) = (bar, foo); + + public object Execute() => Bar.AddDays(Foo); + } +} diff --git a/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs b/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs index 814f30db9..a1f707568 100644 --- a/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs +++ b/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs @@ -10,6 +10,7 @@ using System.IO; using System.Diagnostics; using NBi.Xml.Items; +using NBi.Xml.Variables.Custom; namespace NBi.Testing.Xml.Unit.Variables { @@ -161,5 +162,46 @@ public void Serialize_NoVariable_NothingSerialized() Assert.That(content, Does.Not.Contain(" + { + new GlobalVariableXml + { + Name= "myVar", + Custom = new CustomScalarXml + { + AssemblyPath = "AssemblyPath\\myAssembly.dll", + TypeName = "@VarType", + Parameters = new List + { + new CustomScalarParameterXml{Name="myParam", StringValue="@VarParam"} + } + } + } + } + }; + + var serializer = new XmlSerializer(typeof(TestSuiteXml)); + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream, Encoding.UTF8)) + { + serializer.Serialize(writer, testSuiteXml); + var content = Encoding.UTF8.GetString(stream.ToArray()); + + Debug.WriteLine(content); + + Assert.That(content, Does.Contain("")); + Assert.That(content, Does.Contain("@VarParam")); + } + } } } diff --git a/NBi.Testing/Acceptance/Resources/CustomVariableDaysBetween.cs b/NBi.Testing/Acceptance/Resources/CustomVariableDaysBetween.cs new file mode 100644 index 000000000..ab0e883e7 --- /dev/null +++ b/NBi.Testing/Acceptance/Resources/CustomVariableDaysBetween.cs @@ -0,0 +1,20 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Acceptance.Resources +{ + public class CustomVariableDaysBetween : IScalarResolver + { + private DateTime From { get; } + private DateTime To { get; } + + public CustomVariableDaysBetween(DateTime from, DateTime to) + => (From, To) = (from, to); + + public object Execute() => To.Subtract(From).TotalDays; + } +} diff --git a/NBi.Testing/Acceptance/Resources/Positive/Variable.nbits b/NBi.Testing/Acceptance/Resources/Positive/Variable.nbits index 75eed7b22..ea3f5cff5 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/Variable.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/Variable.nbits @@ -23,6 +23,12 @@ select cast(RAND() as varchar(40)) + + + @januarySecond + @prevcommon + + @@ -114,4 +120,26 @@ + + + + + @daysBetween + select @var; + + + + + + + + 360 + + + 370 + + + + + diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 34f70d249..f917d9744 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -135,6 +135,7 @@ + diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index f6880473d..f39655ff6 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -313,6 +313,8 @@ + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 357ab15f6..464f28ab5 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -520,31 +520,17 @@ - + - + - + - - - - - - - - - - - - - - - + @@ -880,7 +866,7 @@ - + @@ -903,7 +889,7 @@ - + @@ -1919,6 +1905,7 @@ + diff --git a/NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs b/NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs new file mode 100644 index 000000000..a0f7ad18e --- /dev/null +++ b/NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Variables.Custom +{ + public class CustomScalarParameterXml + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlText] + public string StringValue { get; set; } + } +} diff --git a/NBi.Xml/Variables/Custom/CustomScalarXml.cs b/NBi.Xml/Variables/Custom/CustomScalarXml.cs new file mode 100644 index 000000000..204480e99 --- /dev/null +++ b/NBi.Xml/Variables/Custom/CustomScalarXml.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Variables.Custom +{ + public class CustomScalarXml + { + [XmlAttribute("assembly-path")] + public string AssemblyPath { get; set; } + + [XmlAttribute("type")] + public string TypeName { get; set; } + + [XmlElement("parameter")] + public List Parameters { get; set; } = new List(); + } +} diff --git a/NBi.Xml/Variables/GlobalVariableXml.cs b/NBi.Xml/Variables/GlobalVariableXml.cs index 3a1abef2f..16841a43b 100644 --- a/NBi.Xml/Variables/GlobalVariableXml.cs +++ b/NBi.Xml/Variables/GlobalVariableXml.cs @@ -1,4 +1,5 @@ using NBi.Xml.Items; +using NBi.Xml.Variables.Custom; using System; using System.Collections.Generic; using System.Linq; @@ -22,5 +23,7 @@ public class GlobalVariableXml [XmlElement("environment")] public EnvironmentXml Environment { get; set; } + [XmlElement("custom")] + public CustomScalarXml Custom { get; set; } } } diff --git a/NBi.sln b/NBi.sln index 671d9dfda..ba4958370 100644 --- a/NBi.sln +++ b/NBi.sln @@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".project", ".project", "{DA ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml AssemblyInfo.cs = AssemblyInfo.cs + GitVersion.yml = GitVersion.yml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NBi.NUnit", "NBi.NUnit\NBi.NUnit.csproj", "{66314704-AA76-4153-80D8-CA2C5FF06976}" From da9444145bf1f9916bf058114876d92ae0f06835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 5 Nov 2019 21:13:10 +0100 Subject: [PATCH 16/57] Implement the CustomSequenceResolver and acceptance tests --- NBi.Core/NBi.Core.csproj | 2 + .../Resolver/CustomSequenceResolver.cs | 35 ++++++++++ .../Resolver/CustomSequenceResolverArgs.cs | 26 ++++++++ .../Helper/ScalarResolverArgsBuilder.cs | 2 +- .../Helper/SequenceResolverArgsBuilder.cs | 64 ++++++++++--------- NBi.Testing.Core/NBi.Testing.Core.csproj | 3 + .../Resolver/CustomSequenceResolverTest.cs | 46 +++++++++++++ .../Resolver/Resources/MyCustomClass.cs | 19 ++++++ .../Resources/MyCustomClassWithParams.cs | 25 ++++++++ .../Variables/GlobalVariableXmlTest.cs | 6 +- .../Variables/LocalVariableXmlTest.cs | 43 +++++++++++++ .../Resources/CustomSequenceMonths.cs | 27 ++++++++ .../Resources/Positive/MultipleInstance.nbits | 21 +++++- NBi.Testing/NBi.Testing.csproj | 1 + NBi.Xml/NBi.Xml.csproj | 4 +- NBi.Xml/Schema/BaseType.xsd | 1 + ...rParameterXml.cs => CustomParameterXml.cs} | 2 +- .../{CustomScalarXml.cs => CustomXml.cs} | 4 +- NBi.Xml/Variables/GlobalVariableXml.cs | 2 +- NBi.Xml/Variables/Sequence/SequenceXml.cs | 4 ++ 20 files changed, 296 insertions(+), 41 deletions(-) create mode 100644 NBi.Core/Sequence/Resolver/CustomSequenceResolver.cs create mode 100644 NBi.Core/Sequence/Resolver/CustomSequenceResolverArgs.cs create mode 100644 NBi.Testing.Core/Sequence/Resolver/CustomSequenceResolverTest.cs create mode 100644 NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClass.cs create mode 100644 NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClassWithParams.cs create mode 100644 NBi.Testing/Acceptance/Resources/CustomSequenceMonths.cs rename NBi.Xml/Variables/Custom/{CustomScalarParameterXml.cs => CustomParameterXml.cs} (89%) rename NBi.Xml/Variables/Custom/{CustomScalarXml.cs => CustomXml.cs} (73%) diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index ef3a790fe..154478a10 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -709,6 +709,8 @@ + + diff --git a/NBi.Core/Sequence/Resolver/CustomSequenceResolver.cs b/NBi.Core/Sequence/Resolver/CustomSequenceResolver.cs new file mode 100644 index 000000000..517ce3ec1 --- /dev/null +++ b/NBi.Core/Sequence/Resolver/CustomSequenceResolver.cs @@ -0,0 +1,35 @@ +using Microsoft.CSharp; +using NBi.Core.Assemblies; +using NBi.Core.Scalar.Casting; +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Resolver +{ + class CustomSequenceResolver : AbstractCustomFactory, ISequenceResolver + { + private CustomSequenceResolverArgs Args { get; } + + public CustomSequenceResolver(CustomSequenceResolverArgs args) + => Args = args; + + protected override string CustomKind => "custom evaluation of a sequence"; + + public List Execute() + { + var instance = Instantiate(Args); + var value = instance.Execute(); + return value.Cast().ToList(); + } + + IList ISequenceResolver.Execute() => Execute(); + + object IResolver.Execute() => Execute(); + } +} \ No newline at end of file diff --git a/NBi.Core/Sequence/Resolver/CustomSequenceResolverArgs.cs b/NBi.Core/Sequence/Resolver/CustomSequenceResolverArgs.cs new file mode 100644 index 000000000..553f36559 --- /dev/null +++ b/NBi.Core/Sequence/Resolver/CustomSequenceResolverArgs.cs @@ -0,0 +1,26 @@ +using NBi.Core.Assemblies; +using NBi.Core.Query; +using NBi.Core.Query.Resolver; +using NBi.Core.ResultSet.Resolver; +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Resolver +{ + public class CustomSequenceResolverArgs : ISequenceResolverArgs, ICustomArgs + { + public IScalarResolver AssemblyPath { get; } + + public IScalarResolver TypeName { get; } + + public IReadOnlyDictionary Parameters { get; } + + public CustomSequenceResolverArgs(IScalarResolver assemblyPath, IScalarResolver typeName, IDictionary parameters) + => (AssemblyPath, TypeName, Parameters) = (assemblyPath, typeName, new ReadOnlyDictionary(parameters)); + } +} diff --git a/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs index 6d7d683c9..83815405b 100644 --- a/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs @@ -72,7 +72,7 @@ public void Build() case EnvironmentXml obj: args = new EnvironmentScalarResolverArgs(obj.Name); break; - case CustomScalarXml obj: + case CustomXml obj: var helper = new ScalarHelper(ServiceLocator, Context); args = new CustomScalarResolverArgs( helper.InstantiateResolver(obj.AssemblyPath), diff --git a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs index 44da149d9..91d7270dd 100644 --- a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs @@ -7,6 +7,7 @@ using NBi.Core.Sequence.Resolver.Loop; using NBi.Core.Variable; using NBi.Xml.Settings; +using NBi.Xml.Variables.Custom; using NBi.Xml.Variables.Sequence; using System; using System.Collections.Generic; @@ -61,37 +62,42 @@ public void Build() if (!isSetup) throw new InvalidOperationException(); - if (obj is SentinelLoopXml) - { - var loop = obj as SentinelLoopXml; - switch (columnType) - { - case ColumnType.Numeric: - args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); - break; - case ColumnType.DateTime: - args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - else if (obj is FileLoopXml) - { - var loop = obj as FileLoopXml; - args = BuildFileLoopResolverArgs(loop.Path, loop.Pattern); - } - else if (obj is List) + var helper = new ScalarHelper(serviceLocator, new Context(Variables)); + switch (obj) { - var helper = new ScalarHelper(serviceLocator, new Context(Variables)); - var resolvers = new List(); - foreach (var value in obj as List) - resolvers.Add(helper.InstantiateResolver(value)); - args = new ListSequenceResolverArgs(resolvers); + case SentinelLoopXml loop: + switch (columnType) + { + case ColumnType.Numeric: + args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); + break; + case ColumnType.DateTime: + args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); + break; + default: + throw new ArgumentOutOfRangeException(); + } + break; + case FileLoopXml loop: + args = BuildFileLoopResolverArgs(loop.Path, loop.Pattern); + break; + case CustomXml obj: + args = new CustomSequenceResolverArgs( + helper.InstantiateResolver(obj.AssemblyPath), + helper.InstantiateResolver(obj.TypeName), + obj.Parameters.Select(x => new { x.Name, ScalarResolver = (IScalarResolver)helper.InstantiateResolver(x.StringValue) }) + .ToDictionary(x => x.Name, y => y.ScalarResolver) + ); + break; + case List list: + var resolvers = new List(); + foreach (var value in list) + resolvers.Add(helper.InstantiateResolver(value)); + args = new ListSequenceResolverArgs(resolvers); + break; + default: + throw new ArgumentOutOfRangeException(); } - - if (args == null) - throw new ArgumentException(); } public ISequenceResolverArgs GetArgs() => args ?? throw new InvalidOperationException(); diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index b56ac013a..9f969126a 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -227,12 +227,15 @@ + + + diff --git a/NBi.Testing.Core/Sequence/Resolver/CustomSequenceResolverTest.cs b/NBi.Testing.Core/Sequence/Resolver/CustomSequenceResolverTest.cs new file mode 100644 index 000000000..232efd0b3 --- /dev/null +++ b/NBi.Testing.Core/Sequence/Resolver/CustomSequenceResolverTest.cs @@ -0,0 +1,46 @@ +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using NBi.Testing.Core.Sequence.Resolver.Resources; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Sequence.Resolver +{ + public class CustomSequenceResolverTest + { + [Test] + public void Execute_TypeWithoutParam_CorrectEvaluation() + { + var args = new CustomSequenceResolverArgs + ( + new LiteralScalarResolver(GetType().Assembly.Location), + new LiteralScalarResolver($"{typeof(MyCustomClass).Namespace}.{typeof(MyCustomClass).Name}"), + new Dictionary() + ); + var resolver = new CustomSequenceResolver(args); + Assert.That(resolver.Execute(), Has.Member("myFirstValue")); + Assert.That(resolver.Execute(), Has.Member("mySecondValue")); + Assert.That(resolver.Execute(), Has.Member("myThirdValue")); + } + + [Test] + public void Execute_TypeWithParam_CorrectEvaluation() + { + var args = new CustomSequenceResolverArgs + ( + new LiteralScalarResolver(GetType().Assembly.Location), + new LiteralScalarResolver($"{typeof(MyCustomClassWithParams).Namespace}.{typeof(MyCustomClassWithParams).Name}"), + new Dictionary() { { "foo", new LiteralScalarResolver(5) }, { "bar", new LiteralScalarResolver(new DateTime(2019, 1, 1)) } } + ); + var resolver = new CustomSequenceResolver(args); + var output = resolver.Execute(); + Assert.That(output, Has.Member(new DateTime(2019, 1, 6))); + Assert.That(output, Has.Member(new DateTime(2018, 12, 27))); + } + } +} diff --git a/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClass.cs b/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClass.cs new file mode 100644 index 000000000..033a8ea2f --- /dev/null +++ b/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClass.cs @@ -0,0 +1,19 @@ +using NBi.Core; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Sequence.Resolver.Resources +{ + public class MyCustomClass : ISequenceResolver + { + public IList Execute() => new string[] { "myFirstValue", "mySecondValue", "myThirdValue" }.ToList(); + + object IResolver.Execute() => Execute(); + } +} diff --git a/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClassWithParams.cs b/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClassWithParams.cs new file mode 100644 index 000000000..8f5151ca6 --- /dev/null +++ b/NBi.Testing.Core/Sequence/Resolver/Resources/MyCustomClassWithParams.cs @@ -0,0 +1,25 @@ +using NBi.Core; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Sequence.Resolver.Resources +{ + public class MyCustomClassWithParams : ISequenceResolver + { + private int Foo { get; } + private DateTime Bar { get; } + + public MyCustomClassWithParams(DateTime bar, int foo) + => (Bar, Foo) = (bar, foo); + + public IList Execute() => new DateTime[] { Bar.AddDays(-Foo), Bar.AddDays(Foo) }.ToList(); + + object IResolver.Execute() => Execute(); + } +} diff --git a/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs b/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs index a1f707568..575281428 100644 --- a/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs +++ b/NBi.Testing.Xml/Variables/GlobalVariableXmlTest.cs @@ -173,13 +173,13 @@ public void Serialize_CustomEvaluation_CustomElement() new GlobalVariableXml { Name= "myVar", - Custom = new CustomScalarXml + Custom = new CustomXml { AssemblyPath = "AssemblyPath\\myAssembly.dll", TypeName = "@VarType", - Parameters = new List + Parameters = new List { - new CustomScalarParameterXml{Name="myParam", StringValue="@VarParam"} + new CustomParameterXml{Name="myParam", StringValue="@VarParam"} } } } diff --git a/NBi.Testing.Xml/Variables/LocalVariableXmlTest.cs b/NBi.Testing.Xml/Variables/LocalVariableXmlTest.cs index 7f8835c0f..3c133959a 100644 --- a/NBi.Testing.Xml/Variables/LocalVariableXmlTest.cs +++ b/NBi.Testing.Xml/Variables/LocalVariableXmlTest.cs @@ -12,6 +12,7 @@ using NBi.Xml.Items; using System.Reflection; using NBi.Core.ResultSet; +using NBi.Xml.Variables.Custom; namespace NBi.Testing.Xml.Unit.Variables { @@ -115,5 +116,47 @@ public void Serialize_Items_ItemCorrectlySerialized() Assert.That(content, Does.Contain(">Winter<")); } } + + [Test] + public void Serialize_Custom_CustomCorrectlySerialized() + { + var root = new InstanceSettlingXml() + { + Variable = new InstanceVariableXml() + { + Name = "season", + Type = ColumnType.Text, + Custom = new CustomXml + { + AssemblyPath = "AssemblyPath\\myAssembly.dll", + TypeName = "@VarType", + Parameters = new List + { + new CustomParameterXml{Name="myParam", StringValue="@VarParam"} + } + } + } + }; + + var serializer = new XmlSerializer(root.GetType()); + using (var stream = new MemoryStream()) + using (var writer = new StreamWriter(stream, Encoding.UTF8)) + { + serializer.Serialize(writer, root); + var content = Encoding.UTF8.GetString(stream.ToArray()); + + Debug.WriteLine(content); + + Assert.That(content, Does.Contain("")); + Assert.That(content, Does.Contain("@VarParam")); + } + } } } diff --git a/NBi.Testing/Acceptance/Resources/CustomSequenceMonths.cs b/NBi.Testing/Acceptance/Resources/CustomSequenceMonths.cs new file mode 100644 index 000000000..13f2e42c5 --- /dev/null +++ b/NBi.Testing/Acceptance/Resources/CustomSequenceMonths.cs @@ -0,0 +1,27 @@ +using NBi.Core; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Acceptance.Resources +{ + public class CustomSequenceMonths : ISequenceResolver + { + public CustomSequenceMonths() + { } + + object IResolver.Execute() => Execute(); + + public IList Execute() => new DateTime[] + { + new DateTime(2016, 1, 1), + new DateTime(2016, 2, 1), + new DateTime(2016, 3, 1) + }; + } +} diff --git a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits index df5fdbbe7..f112b2793 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits @@ -284,7 +284,7 @@ @@ -366,4 +366,21 @@ --> + + + + + + + + + + + + + + + + + diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index f917d9744..1c5dcf7a1 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -135,6 +135,7 @@ + diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index f39655ff6..2676ec6f4 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -313,8 +313,8 @@ - - + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 464f28ab5..70db2b379 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1288,6 +1288,7 @@ + diff --git a/NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs b/NBi.Xml/Variables/Custom/CustomParameterXml.cs similarity index 89% rename from NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs rename to NBi.Xml/Variables/Custom/CustomParameterXml.cs index a0f7ad18e..feaa1e3a2 100644 --- a/NBi.Xml/Variables/Custom/CustomScalarParameterXml.cs +++ b/NBi.Xml/Variables/Custom/CustomParameterXml.cs @@ -7,7 +7,7 @@ namespace NBi.Xml.Variables.Custom { - public class CustomScalarParameterXml + public class CustomParameterXml { [XmlAttribute("name")] public string Name { get; set; } diff --git a/NBi.Xml/Variables/Custom/CustomScalarXml.cs b/NBi.Xml/Variables/Custom/CustomXml.cs similarity index 73% rename from NBi.Xml/Variables/Custom/CustomScalarXml.cs rename to NBi.Xml/Variables/Custom/CustomXml.cs index 204480e99..d9e8c00ea 100644 --- a/NBi.Xml/Variables/Custom/CustomScalarXml.cs +++ b/NBi.Xml/Variables/Custom/CustomXml.cs @@ -7,7 +7,7 @@ namespace NBi.Xml.Variables.Custom { - public class CustomScalarXml + public class CustomXml { [XmlAttribute("assembly-path")] public string AssemblyPath { get; set; } @@ -16,6 +16,6 @@ public class CustomScalarXml public string TypeName { get; set; } [XmlElement("parameter")] - public List Parameters { get; set; } = new List(); + public List Parameters { get; set; } = new List(); } } diff --git a/NBi.Xml/Variables/GlobalVariableXml.cs b/NBi.Xml/Variables/GlobalVariableXml.cs index 16841a43b..d1d1d1acb 100644 --- a/NBi.Xml/Variables/GlobalVariableXml.cs +++ b/NBi.Xml/Variables/GlobalVariableXml.cs @@ -24,6 +24,6 @@ public class GlobalVariableXml public EnvironmentXml Environment { get; set; } [XmlElement("custom")] - public CustomScalarXml Custom { get; set; } + public CustomXml Custom { get; set; } } } diff --git a/NBi.Xml/Variables/Sequence/SequenceXml.cs b/NBi.Xml/Variables/Sequence/SequenceXml.cs index 73bc67ac9..bc93894c6 100644 --- a/NBi.Xml/Variables/Sequence/SequenceXml.cs +++ b/NBi.Xml/Variables/Sequence/SequenceXml.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Xml.Variables.Custom; using System; using System.Collections.Generic; using System.Linq; @@ -25,6 +26,9 @@ public class SequenceXml [XmlElement("loop-file")] public FileLoopXml FileLoop { get; set; } + [XmlElement("custom")] + public CustomXml Custom { get; set; } + [XmlIgnore] public bool ItemsSpecified { get => Items.Count > 0; set { } } } From 4ff881d85ab24155a5c490594895eea0526c2ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 9 Nov 2019 11:18:22 +0100 Subject: [PATCH 17/57] Create a new EmptyResultSetResolver and support xml serailization, including acceptance tests --- NBi.Core/NBi.Core.csproj | 2 + .../Resolver/EmptyResultSetResolver.cs | 37 ++++++++++ .../Resolver/EmptyResultSetResolverArgs.cs | 25 +++++++ .../Resolver/ResultSetResolverFactory.cs | 1 + .../Helper/ResultSetResolverArgsBuilder.cs | 16 +++++ NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + .../Resolver/EmptyResultSetResolverTest.cs | 66 ++++++++++++++++++ .../Resources/ResultSetSystemXmlTestSuite.xml | 15 ++++ .../Systems/ResultSetSystemXmlTest.cs | 69 ++++++++++++++++++- .../Positive/ResultSetConstraint.nbits | 53 ++++++++++++++ NBi.Xml/Items/ResultSet/EmptyResultSetXml.cs | 27 ++++++++ NBi.Xml/NBi.Xml.csproj | 1 + NBi.Xml/Schema/BaseType.xsd | 7 ++ NBi.Xml/Systems/ResultSetSystemXml.cs | 3 + 14 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 NBi.Core/ResultSet/Resolver/EmptyResultSetResolver.cs create mode 100644 NBi.Core/ResultSet/Resolver/EmptyResultSetResolverArgs.cs create mode 100644 NBi.Testing.Core/ResultSet/Resolver/EmptyResultSetResolverTest.cs create mode 100644 NBi.Xml/Items/ResultSet/EmptyResultSetXml.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 154478a10..a65cac18b 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -519,6 +519,8 @@ + + diff --git a/NBi.Core/ResultSet/Resolver/EmptyResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/EmptyResultSetResolver.cs new file mode 100644 index 000000000..733b84438 --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/EmptyResultSetResolver.cs @@ -0,0 +1,37 @@ +using NBi.Core.Query; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Resolver +{ + public class EmptyResultSetResolver : IResultSetResolver + { + private EmptyResultSetResolverArgs Args { get; } + + public EmptyResultSetResolver(EmptyResultSetResolverArgs args) + => Args = args; + + public virtual ResultSet Execute() + { + var dataTable = new DataTable(); + if (Args.Identifiers != null) + foreach (var identifier in Args.Identifiers) + dataTable.Columns.Add(new DataColumn(identifier.Name, typeof(object))); + + if (Args.ColumnCount!=null && dataTable.Columns.Count< Args.ColumnCount.Execute()) + { + var missingColumnCount = Args.ColumnCount.Execute() - dataTable.Columns.Count; + for (int i = 0; i < missingColumnCount; i++) + dataTable.Columns.Add(new DataColumn($"Column_{dataTable.Columns.Count}", typeof(object))); + } + + var rs = new ResultSet(); + rs.Load(dataTable); + return rs; + } + } +} diff --git a/NBi.Core/ResultSet/Resolver/EmptyResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/EmptyResultSetResolverArgs.cs new file mode 100644 index 000000000..9750eeb74 --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/EmptyResultSetResolverArgs.cs @@ -0,0 +1,25 @@ +using NBi.Core.Query; +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Resolver +{ + public class EmptyResultSetResolverArgs : ResultSetResolverArgs + { + public IScalarResolver ColumnCount { get; } = null; + public IEnumerable Identifiers { get; } = null; + public EmptyResultSetResolverArgs(IEnumerable columns, IScalarResolver columnCount) + => (Identifiers, ColumnCount) = (columns, columnCount); + + public EmptyResultSetResolverArgs(IEnumerable columns) + => (Identifiers, ColumnCount) = (columns, null); + + public EmptyResultSetResolverArgs(IScalarResolver columnCount) + => (ColumnCount) = (columnCount); + } +} diff --git a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs index da1449aa9..d72d01bbd 100644 --- a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs +++ b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs @@ -37,6 +37,7 @@ public IResultSetResolver Instantiate(ResultSetResolverArgs args) case XPathResultSetResolverArgs x: return new XPathResultSetResolver(x); case ObjectsResultSetResolverArgs x: return new ObjectsResultSetResolver(x); case SequenceCombinationResultSetResolverArgs x: return new SequenceCombinationResultSetResolver(x); + case EmptyResultSetResolverArgs x: return new EmptyResultSetResolver(x); default: throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a ResultSet"); } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index ff04fd9da..8f42b1872 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -73,6 +73,8 @@ public void Build() args = BuildXPathResolverArgs((obj as ResultSetSystemXml).XmlSource); else if ((obj as ResultSetSystemXml).JsonSource != null) args = BuildJsonPathResolverArgs((obj as ResultSetSystemXml).JsonSource); + else if ((obj as ResultSetSystemXml).Empty != null) + args = BuildEmptyResolverArgs((obj as ResultSetSystemXml).Empty); //ResultSet (embedded) else if ((obj as ResultSetSystemXml).Rows != null) args = BuildEmbeddedResolverArgs((obj as ResultSetSystemXml).Content); @@ -249,6 +251,20 @@ private ResultSetResolverArgs BuildJsonPathResolverArgs(JsonSourceXml jsonSource return new XPathResultSetResolverArgs(engine); } + private ResultSetResolverArgs BuildEmptyResolverArgs(EmptyResultSetXml empty) + { + var scalarHelper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); + + if (empty.Columns.Count > 0 && !string.IsNullOrEmpty(empty.ColumnCount)) + return new EmptyResultSetResolverArgs(empty.Columns.Select(x => x.Identifier as ColumnNameIdentifier), scalarHelper.InstantiateResolver(empty.ColumnCount)); + else if (empty.Columns.Count > 0) + return new EmptyResultSetResolverArgs(empty.Columns.Select(x => x.Identifier as ColumnNameIdentifier)); + else if (!string.IsNullOrEmpty(empty.ColumnCount)) + return new EmptyResultSetResolverArgs(scalarHelper.InstantiateResolver(empty.ColumnCount)); + else + throw new ArgumentNullException(); + } + public ResultSetResolverArgs GetArgs() => args; } } diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 9f969126a..e4a009b8d 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -183,6 +183,7 @@ + diff --git a/NBi.Testing.Core/ResultSet/Resolver/EmptyResultSetResolverTest.cs b/NBi.Testing.Core/ResultSet/Resolver/EmptyResultSetResolverTest.cs new file mode 100644 index 000000000..c4e09c07b --- /dev/null +++ b/NBi.Testing.Core/ResultSet/Resolver/EmptyResultSetResolverTest.cs @@ -0,0 +1,66 @@ +using NBi.Core.ResultSet.Combination; +using NBi.Core.ResultSet.Resolver; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core.Injection; +using NBi.Core.ResultSet; +using Moq; + +namespace NBi.Testing.Core.ResultSet.Resolver +{ + public class EmptyResultSetResolverTest + { + [Test()] + public void Instantiate_ColumnsBased_CorrectType() + { + var args = new EmptyResultSetResolverArgs( + new List + { + new ColumnNameIdentifier("myFirstColumn"), + new ColumnNameIdentifier("mySecondColumn"), + } + ); + var resolver = new EmptyResultSetResolver(args); + + var rs = resolver.Execute(); + Assert.That(rs.Columns.Count, Is.EqualTo(2)); + Assert.That(rs.Columns[0].ColumnName, Is.EqualTo("myFirstColumn")); + Assert.That(rs.Columns[1].ColumnName, Is.EqualTo("mySecondColumn")); + } + + [Test()] + public void Instantiate_ColumnCountBased_CorrectType() + { + var args = new EmptyResultSetResolverArgs(new LiteralScalarResolver(4)); + var resolver = new EmptyResultSetResolver(args); + + var rs = resolver.Execute(); + Assert.That(rs.Columns.Count, Is.EqualTo(4)); + } + + [Test()] + public void Instantiate_ColumnsAndColumnCountBased_CorrectType() + { + var args = new EmptyResultSetResolverArgs( + new List + { + new ColumnNameIdentifier("myFirstColumn"), + new ColumnNameIdentifier("mySecondColumn"), + }, new LiteralScalarResolver(4) + ); + var resolver = new EmptyResultSetResolver(args); + + var rs = resolver.Execute(); + Assert.That(rs.Columns.Count, Is.EqualTo(4)); + Assert.That(rs.Columns[0].ColumnName, Is.EqualTo("myFirstColumn")); + Assert.That(rs.Columns[1].ColumnName, Is.EqualTo("mySecondColumn")); + } + } +} \ No newline at end of file diff --git a/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml b/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml index da862cbb7..d5e509ff3 100644 --- a/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml +++ b/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml @@ -306,4 +306,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs index 7b4381bd1..6f78b84f2 100644 --- a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs +++ b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs @@ -400,6 +400,29 @@ public void Deserialize_SampleFile_AlterationLookupReplace() Assert.That(lookup.Replacement.Identifier.Label, Is.EqualTo("#1")); } + [Test] + public void Deserialize_SampleFile_EmptyResultSet() + { + int testNr = 18; + + // Create an instance of the XmlSerializer specifying type and namespace. + var ts = DeserializeSample(); + + // Check the properties of the object. + Assert.That(ts.Tests[testNr].Systems[0], Is.AssignableTo()); + var rs = ts.Tests[testNr].Systems[0] as ResultSetSystemXml; + + Assert.That(rs.Empty, Is.Not.Null); + Assert.That(rs.Empty, Is.TypeOf()); + var empty = rs.Empty as EmptyResultSetXml; + + Assert.That(empty.ColumnCount, Is.EqualTo(4)); + Assert.That(empty.Columns, Has.Count.EqualTo(2)); + + Assert.That(empty.Columns.Any(x => x.Identifier.Label == "[myFirstColumn]")); + Assert.That(empty.Columns.Any(x => x.Identifier.Label == "[mySecondColumn]")); + } + [Test] public void Serialize_FileAndParser_Correct() { @@ -469,7 +492,7 @@ public void Serialize_Renaming_Correct() { File = new FileXml() { Path = @"C:\Temp\foo.txt" }, Alterations = new List() - { + { new RenamingXml() { Identifier= new ColumnOrdinalIdentifier(5), NewName = "myNewName" } } @@ -513,8 +536,8 @@ public void Serialize_Unstack_Correct() { new UnstackXml() { - Header = new HeaderXml() - { + Header = new HeaderXml() + { Column = new ColumnDefinitionLightXml() { Identifier= new ColumnOrdinalIdentifier(2), Type= ColumnType.Text }, EnforcedValues = new List() { @@ -665,5 +688,45 @@ public void Serialize_Sequence_Correct() Assert.That(xml, Does.Contain("A")); Assert.That(xml, Does.Contain("B")); } + + [Test] + public void Serialize_EmptyWithoutColumnCount_Correct() + { + var root = new ResultSetSystemXml() + { + Empty = new EmptyResultSetXml() + { + Columns = new List + { + new ColumnDefinitionLightXml {Identifier = new ColumnNameIdentifier("myFirstColumn")}, + new ColumnDefinitionLightXml {Identifier = new ColumnNameIdentifier("mySecondColumn")} + } + } + }; + + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain("")); + Assert.That(xml, Does.Contain("")); + Assert.That(xml, Does.Contain("")); + Assert.That(xml, Does.Not.Contain("column-count")); + } + + [Test] + public void Serialize_EmptyWithoutColumns_Correct() + { + var root = new ResultSetSystemXml() + { + Empty = new EmptyResultSetXml { ColumnCount = "4" } + }; + + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain(" + + + + + + + + + + + + + + + + ..\Csv\ResellerOrderCountByYearBefore2006.csv + + + + + + + 10000 + + + + + + + + + + + + + + + + + + ..\Csv\ResellerOrderCountByYearBefore2006.csv + + + + + 10000 + + + + + + + diff --git a/NBi.Xml/Items/ResultSet/EmptyResultSetXml.cs b/NBi.Xml/Items/ResultSet/EmptyResultSetXml.cs new file mode 100644 index 000000000..f59a77ca2 --- /dev/null +++ b/NBi.Xml/Items/ResultSet/EmptyResultSetXml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.ResultSet +{ + public class EmptyResultSetXml + { + [XmlAttribute("column-count")] + [DefaultValue("")] + public string ColumnCount { get; set; } + + [XmlElement("column")] + public List Columns { get; set; } = new List(); + + [XmlIgnore] + public bool ColumnsSpecified + { + get => (Columns?.Count ?? 0) != 0; + set { return; } + } + } +} diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 2676ec6f4..dfe77be2a 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -198,6 +198,7 @@ + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index a5e2f4fab..66a4d43ec 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1608,11 +1608,18 @@ + + + + + + + diff --git a/NBi.Xml/Systems/ResultSetSystemXml.cs b/NBi.Xml/Systems/ResultSetSystemXml.cs index 5d15ff979..8d4aef61c 100644 --- a/NBi.Xml/Systems/ResultSetSystemXml.cs +++ b/NBi.Xml/Systems/ResultSetSystemXml.cs @@ -110,6 +110,9 @@ public override BaseItem BaseItem [XmlElement("json-source")] public virtual JsonSourceXml JsonSource { get; set; } + [XmlElement("empty")] + public virtual EmptyResultSetXml Empty { get; set; } + [XmlIgnore] public bool SequenceCombinationSpecified { get => SequenceCombination != null; set { } } From d4e5493fbc3dbc97e688ee2517df2802cb855452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 9 Nov 2019 14:19:38 +0100 Subject: [PATCH 18/57] Fix failing test --- NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs index 6f78b84f2..c6164e6a3 100644 --- a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs +++ b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs @@ -416,7 +416,7 @@ public void Deserialize_SampleFile_EmptyResultSet() Assert.That(rs.Empty, Is.TypeOf()); var empty = rs.Empty as EmptyResultSetXml; - Assert.That(empty.ColumnCount, Is.EqualTo(4)); + Assert.That(empty.ColumnCount, Is.EqualTo("4")); Assert.That(empty.Columns, Has.Count.EqualTo(2)); Assert.That(empty.Columns.Any(x => x.Identifier.Label == "[myFirstColumn]")); From 12f0b36bb9ec354f7edd275ca21f3ed1e3a68879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sat, 9 Nov 2019 14:20:01 +0100 Subject: [PATCH 19/57] Implement if-unavailable and add acceptance tests --- NBi.Core/NBi.Core.csproj | 3 + .../IfUnavailableResultSetResolver.cs | 30 +++++ .../IfUnavailableResultSetResolverArgs.cs | 20 +++ .../Resolver/ResultSetResolverFactory.cs | 3 +- .../Resolver/ResultSetUnavailableException.cs | 15 +++ .../Resolver/XPathResultSetResolver.cs | 20 ++- .../Helper/ResultSetResolverArgsBuilder.cs | 115 ++++++++++-------- NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + .../IfUnavailableResultSetResolverTest.cs | 78 ++++++++++++ .../Resources/ResultSetSystemXmlTestSuite.xml | 26 ++++ .../Systems/ResultSetSystemXmlTest.cs | 37 +++++- .../Positive/ResultSetConstraint.nbits | 35 +++++- NBi.Xml/Items/ResultSet/IfUnavailableXml.cs | 16 +++ NBi.Xml/NBi.Xml.csproj | 1 + NBi.Xml/Schema/BaseType.xsd | 6 + NBi.Xml/Systems/ResultSetSystemXml.cs | 3 + 16 files changed, 349 insertions(+), 60 deletions(-) create mode 100644 NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolver.cs create mode 100644 NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolverArgs.cs create mode 100644 NBi.Core/ResultSet/Resolver/ResultSetUnavailableException.cs create mode 100644 NBi.Testing.Core/ResultSet/Resolver/IfUnavailableResultSetResolverTest.cs create mode 100644 NBi.Xml/Items/ResultSet/IfUnavailableXml.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index a65cac18b..2b48937d2 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -521,6 +521,9 @@ + + + diff --git a/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolver.cs new file mode 100644 index 000000000..a3f33a9cc --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolver.cs @@ -0,0 +1,30 @@ +using NBi.Core.Injection; +using NBi.Core.Query; +using NBi.Core.Query.Execution; +using NBi.Core.Query.Resolver; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Extensibility.Query; + +namespace NBi.Core.ResultSet.Resolver +{ + class IfUnavailableResultSetResolver : IResultSetResolver + { + private IfUnavailableResultSetResolverArgs Args { get; } + + public IfUnavailableResultSetResolver(IfUnavailableResultSetResolverArgs args) + => Args = args; + + public ResultSet Execute() + { + try + { return Args.Primary.Execute(); } + catch (ResultSetUnavailableException) + { return Args.Secondary.Execute(); } + } + } +} diff --git a/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolverArgs.cs new file mode 100644 index 000000000..ff888d8d0 --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/IfUnavailableResultSetResolverArgs.cs @@ -0,0 +1,20 @@ +using NBi.Core.Query; +using NBi.Core.Query.Resolver; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Resolver +{ + public class IfUnavailableResultSetResolverArgs : ResultSetResolverArgs + { + public IResultSetResolver Primary { get; } + public IResultSetResolver Secondary { get; } + + public IfUnavailableResultSetResolverArgs(IResultSetResolver primary, IResultSetResolver secondary) + => (Primary, Secondary) = (primary, secondary); + } +} \ No newline at end of file diff --git a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs index d72d01bbd..8d44eeb47 100644 --- a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs +++ b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs @@ -38,7 +38,8 @@ public IResultSetResolver Instantiate(ResultSetResolverArgs args) case ObjectsResultSetResolverArgs x: return new ObjectsResultSetResolver(x); case SequenceCombinationResultSetResolverArgs x: return new SequenceCombinationResultSetResolver(x); case EmptyResultSetResolverArgs x: return new EmptyResultSetResolver(x); - default: throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a ResultSet"); + case IfUnavailableResultSetResolverArgs x: return new IfUnavailableResultSetResolver(x); + default: throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a result-set"); } } } diff --git a/NBi.Core/ResultSet/Resolver/ResultSetUnavailableException.cs b/NBi.Core/ResultSet/Resolver/ResultSetUnavailableException.cs new file mode 100644 index 000000000..1fa83bf0f --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/ResultSetUnavailableException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Resolver +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2237:Mark ISerializable types with serializable", Justification = "")] + public class ResultSetUnavailableException : Exception + { + public ResultSetUnavailableException(Exception innerException) + : base("Result-set is not available", innerException) { } + } +} diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs index 9db498cd1..6198917c6 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs +++ b/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using NBi.Extensibility; namespace NBi.Core.ResultSet.Resolver { @@ -18,14 +19,21 @@ public XPathResultSetResolver(XPathResultSetResolverArgs args) public virtual ResultSet Execute() { - var objects = Args.XPathEngine.Execute(); + try + { + var objects = Args.XPathEngine.Execute(); - var helper = new ObjectsToRowsHelper(); - var rows = helper.Execute(objects); + var helper = new ObjectsToRowsHelper(); + var rows = helper.Execute(objects); - var rs = new ResultSet(); - rs.Load(rows); - return rs; + var rs = new ResultSet(); + rs.Load(rows); + return rs; + } + catch (NBiException ex) + { + throw new ResultSetUnavailableException(ex); + } } } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 8f42b1872..27c3d4391 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -56,65 +56,71 @@ public void Build() if (!isSetup) throw new InvalidOperationException(); - if (obj is ResultSetSystemXml) + switch (obj) { - //ResultSet (external flat file) - if (!(obj as ResultSetSystemXml)?.File?.IsEmpty() ?? false) - args = BuildFlatFileResultSetResolverArgs((obj as ResultSetSystemXml).File); - //Query - else if ((obj as ResultSetSystemXml).Query != null) - args = BuildQueryResolverArgs((obj as ResultSetSystemXml).Query, scope); - //Sequences combination - else if ((obj as ResultSetSystemXml).SequenceCombination != null) - args = BuildSequenceCombinationResolverArgs((obj as ResultSetSystemXml).SequenceCombination); - else if ((obj as ResultSetSystemXml).Sequence != null) - args = BuildSequenceResolverArgs((obj as ResultSetSystemXml).Sequence); - else if ((obj as ResultSetSystemXml).XmlSource != null) - args = BuildXPathResolverArgs((obj as ResultSetSystemXml).XmlSource); - else if ((obj as ResultSetSystemXml).JsonSource != null) - args = BuildJsonPathResolverArgs((obj as ResultSetSystemXml).JsonSource); - else if ((obj as ResultSetSystemXml).Empty != null) - args = BuildEmptyResolverArgs((obj as ResultSetSystemXml).Empty); - //ResultSet (embedded) - else if ((obj as ResultSetSystemXml).Rows != null) - args = BuildEmbeddedResolverArgs((obj as ResultSetSystemXml).Content); + case ResultSetSystemXml x: args = BuildResultSetSystemXml(x); break; + case ResultSetXml x: args = BuildResultSetXml(x); break; + case IfMissingXml x when !(x?.File?.IsEmpty() ?? false): args = BuildFlatFileResultSetResolverArgs(x.File); break; + case QueryXml x: args = BuildQueryResolverArgs(x, scope); break; + case XmlSourceXml x: args = BuildXPathResolverArgs(x); break; + case JsonSourceXml x: args = BuildJsonPathResolverArgs(x); break; + default: throw new ArgumentException(); } + } - if (obj is IfMissingXml) - { - //ResultSet (external flat file) - if (!(obj as IfMissingXml)?.File?.IsEmpty() ?? false) - args = BuildFlatFileResultSetResolverArgs((obj as IfMissingXml).File); - } + private ResultSetResolverArgs BuildResultSetSystemXml(ResultSetSystemXml xml) + { + if (xml?.IfUnavailable?.ResultSet != null) + return BuildIfUnavaibleResultSetResolverArgs(BuildInternalResultSetSystemXml(xml), BuildResultSetSystemXml(xml.IfUnavailable.ResultSet)); + else + return BuildInternalResultSetSystemXml(xml); + } + + private ResultSetResolverArgs BuildInternalResultSetSystemXml(ResultSetSystemXml xml) + { + //ResultSet (external flat file) + if (!xml?.File?.IsEmpty() ?? false) + return BuildFlatFileResultSetResolverArgs(xml.File); + //Query + else if (xml.Query != null) + return BuildQueryResolverArgs(xml.Query, scope); + //Sequences combination + else if (xml.SequenceCombination != null) + return BuildSequenceCombinationResolverArgs(xml.SequenceCombination); + else if (xml.Sequence != null) + return BuildSequenceResolverArgs(xml.Sequence); + else if (xml.XmlSource != null) + return BuildXPathResolverArgs(xml.XmlSource); + else if (xml.JsonSource != null) + return BuildJsonPathResolverArgs(xml.JsonSource); + else if (xml.Empty != null) + return BuildEmptyResolverArgs(xml.Empty); + //ResultSet (embedded) + else if (xml.Rows != null) + return BuildEmbeddedResolverArgs(xml.Content); + + throw new ArgumentException(); + } - if (obj is ResultSetXml) + private ResultSetResolverArgs BuildResultSetXml(ResultSetXml xml) + { + //ResultSet (external flat file) + if (!string.IsNullOrEmpty(xml.File)) { - //ResultSet (external flat file) - if (!string.IsNullOrEmpty((obj as ResultSetXml).File)) - { - ParseFileInfo((obj as ResultSetXml).File, out var filename, out var parserName); - if (string.IsNullOrEmpty(parserName)) - args = BuildFlatFileResultSetResolverArgs(new FileXml() { Path = filename }); - else - args = BuildFlatFileResultSetResolverArgs(new FileXml() { Path = filename, Parser = new ParserXml() { Name = parserName } }); - } - //ResultSet (embedded) - else if ((obj as ResultSetXml).Rows != null) - args = BuildEmbeddedResolverArgs((obj as ResultSetXml).Content); + ParseFileInfo(xml.File, out var filename, out var parserName); + if (string.IsNullOrEmpty(parserName)) + return BuildFlatFileResultSetResolverArgs(new FileXml() { Path = filename }); + else + return BuildFlatFileResultSetResolverArgs(new FileXml() { Path = filename, Parser = new ParserXml() { Name = parserName } }); } + //ResultSet (embedded) + else if (xml.Rows != null) + return BuildEmbeddedResolverArgs(xml.Content); - if (obj is QueryXml) - args = BuildQueryResolverArgs((obj as QueryXml), scope); - - if (obj is XmlSourceXml) - args = BuildXPathResolverArgs((obj as XmlSourceXml)); - if (obj is JsonSourceXml) - args = BuildJsonPathResolverArgs((obj as JsonSourceXml)); - - if (args == null) - throw new ArgumentException(); + throw new ArgumentException(); } + private ResultSetResolverArgs BuildSequenceCombinationResolverArgs(SequenceCombinationXml sequenceCombinationXml) { var resolvers = new List(); @@ -202,7 +208,6 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) var helper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); - XPathEngine engine = null; if (xmlSource.File != null) { @@ -265,6 +270,14 @@ private ResultSetResolverArgs BuildEmptyResolverArgs(EmptyResultSetXml empty) throw new ArgumentNullException(); } + private ResultSetResolverArgs BuildIfUnavaibleResultSetResolverArgs(ResultSetResolverArgs primaryArgs, ResultSetResolverArgs secondaryArgs) + { + var factory = ServiceLocator.GetResultSetResolverFactory(); + var primary = factory.Instantiate(primaryArgs); + var secondary = factory.Instantiate(secondaryArgs); + return new IfUnavailableResultSetResolverArgs(primary, secondary); + } + public ResultSetResolverArgs GetArgs() => args; } } diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index e4a009b8d..8ca518e3a 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -183,6 +183,7 @@ + diff --git a/NBi.Testing.Core/ResultSet/Resolver/IfUnavailableResultSetResolverTest.cs b/NBi.Testing.Core/ResultSet/Resolver/IfUnavailableResultSetResolverTest.cs new file mode 100644 index 000000000..53de2f166 --- /dev/null +++ b/NBi.Testing.Core/ResultSet/Resolver/IfUnavailableResultSetResolverTest.cs @@ -0,0 +1,78 @@ +using NBi.Core.ResultSet.Combination; +using NBi.Core.ResultSet.Resolver; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core.Injection; +using NBi.Core.ResultSet; +using Moq; + +namespace NBi.Testing.Core.ResultSet.Resolver +{ + public class IfUnavailableResultSetResolverTest + { + [Test] + public void Execute_PrimaryFailing_SecondaryExecuted() + { + var primary = Mock.Of(); + Mock.Get(primary).Setup(x => x.Execute()).Throws(new ResultSetUnavailableException(null)); + var secondary = Mock.Of(); + var expectedRs = new NBi.Core.ResultSet.ResultSet(); + Mock.Get(secondary).Setup(x => x.Execute()).Returns(expectedRs); + + var args = new IfUnavailableResultSetResolverArgs(primary, secondary); + var resolver = new IfUnavailableResultSetResolver(args); + + var rs = resolver.Execute(); + Mock.Get(primary).Verify(x => x.Execute(), Times.Once); + Mock.Get(secondary).Verify(x => x.Execute(), Times.Once); + Assert.That(rs, Is.EqualTo(expectedRs)); + } + + [Test] + public void Execute_PrimarySuccessful_SecondaryNotExecuted() + { + var expectedRs = new NBi.Core.ResultSet.ResultSet(); + var primary = Mock.Of(); + Mock.Get(primary).Setup(x => x.Execute()).Returns(expectedRs); + var secondary = Mock.Of(); + Mock.Get(secondary).Setup(x => x.Execute()).Throws(new ResultSetUnavailableException(null)); + + var args = new IfUnavailableResultSetResolverArgs(primary, secondary); + var resolver = new IfUnavailableResultSetResolver(args); + + var rs = resolver.Execute(); + Mock.Get(primary).Verify(x => x.Execute(), Times.Once); + Mock.Get(secondary).Verify(x => x.Execute(), Times.Never); + Assert.That(rs, Is.EqualTo(expectedRs)); + } + + [Test] + public void Execute_PrimaryFailingSecondaryFailing_TertiaryNotExecuted() + { + var expectedRs = new NBi.Core.ResultSet.ResultSet(); + var primary = Mock.Of(); + Mock.Get(primary).Setup(x => x.Execute()).Throws(new ResultSetUnavailableException(null)); + var secondary = Mock.Of(); + Mock.Get(secondary).Setup(x => x.Execute()).Throws(new ResultSetUnavailableException(null)); + var tertiary = Mock.Of(); + Mock.Get(tertiary).Setup(x => x.Execute()).Returns(expectedRs); + + var secondaryArgs = new IfUnavailableResultSetResolverArgs(secondary, tertiary); + var args = new IfUnavailableResultSetResolverArgs(primary, new IfUnavailableResultSetResolver(secondaryArgs)); + var resolver = new IfUnavailableResultSetResolver(args); + + var rs = resolver.Execute(); + Mock.Get(primary).Verify(x => x.Execute(), Times.Once); + Mock.Get(secondary).Verify(x => x.Execute(), Times.Once); + Mock.Get(tertiary).Verify(x => x.Execute(), Times.Once); + Assert.That(rs, Is.EqualTo(expectedRs)); + } + } +} \ No newline at end of file diff --git a/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml b/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml index d5e509ff3..4505b5d5c 100644 --- a/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml +++ b/NBi.Testing.Xml/Resources/ResultSetSystemXmlTestSuite.xml @@ -321,4 +321,30 @@ + + + + + + xmlSource.xml + + + //element + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs index c6164e6a3..710d59bc2 100644 --- a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs +++ b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs @@ -423,6 +423,23 @@ public void Deserialize_SampleFile_EmptyResultSet() Assert.That(empty.Columns.Any(x => x.Identifier.Label == "[mySecondColumn]")); } + [Test] + public void Deserialize_SampleFile_IfUnavailable() + { + int testNr = 19; + + // Create an instance of the XmlSerializer specifying type and namespace. + var ts = DeserializeSample(); + + // Check the properties of the object. + Assert.That(ts.Tests[testNr].Systems[0], Is.AssignableTo()); + var rs = ts.Tests[testNr].Systems[0] as ResultSetSystemXml; + + Assert.That(rs.IfUnavailable, Is.Not.Null); + Assert.That(rs.IfUnavailable.ResultSet, Is.Not.Null); + Assert.That(rs.IfUnavailable.ResultSet.Empty, Is.Not.Null); + } + [Test] public void Serialize_FileAndParser_Correct() { @@ -658,7 +675,7 @@ public void Serialize_LookupReplaceDefaultMissing_Correct() { new LookupReplaceXml() { - Missing = new NBi.Xml.Items.Alteration.Lookup.MissingXml() { Behavior= Behavior.Failure }, + Missing = new MissingXml() { Behavior= Behavior.Failure }, } } }; @@ -728,5 +745,23 @@ public void Serialize_EmptyWithoutColumns_Correct() Assert.That(xml, Does.Contain("column-count=\"4\"")); Assert.That(xml, Does.Not.Contain(" - + @@ -561,6 +561,39 @@ + + + + + ..\Csv\NonExisting.xml + + //PurchaseOrder/Items/Item + + + + + + + be + fr + + + + + + + + + + fr + + + be + + + + + diff --git a/NBi.Xml/Items/ResultSet/IfUnavailableXml.cs b/NBi.Xml/Items/ResultSet/IfUnavailableXml.cs new file mode 100644 index 000000000..c4b4ecdd1 --- /dev/null +++ b/NBi.Xml/Items/ResultSet/IfUnavailableXml.cs @@ -0,0 +1,16 @@ +using NBi.Xml.Systems; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.ResultSet +{ + public class IfUnavailableXml + { + [XmlElement("result-set")] + public virtual ResultSetSystemXml ResultSet { get; set; } + } +} diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index dfe77be2a..10a776674 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -199,6 +199,7 @@ + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 66a4d43ec..fed7b831a 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1611,9 +1611,15 @@ + + + + + + diff --git a/NBi.Xml/Systems/ResultSetSystemXml.cs b/NBi.Xml/Systems/ResultSetSystemXml.cs index 8d4aef61c..75b1ac234 100644 --- a/NBi.Xml/Systems/ResultSetSystemXml.cs +++ b/NBi.Xml/Systems/ResultSetSystemXml.cs @@ -137,6 +137,9 @@ public bool AlterationsSpecified set {} } + [XmlElement("if-unavailable")] + public virtual IfUnavailableXml IfUnavailable { get; set; } + public override ICollection GetAutoCategories() { return new List() { "Result-set" }; From e7f9816996706e3ab78f5f37ce89be17be6b7924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 11 Nov 2019 11:14:31 +0100 Subject: [PATCH 20/57] Implement the two new transformations and unit tests --- .../Native/Text/TextTransformations.cs | 23 ++++++++++++++++++ .../Transformer/Native/TextTest.cs | 24 +++++++++++++++++++ .../NativeTransformationFactoryTest.cs | 2 ++ NBi.Xml/Schema/BaseType.xsd | 2 ++ 4 files changed, 51 insertions(+) diff --git a/NBi.Core/Transformation/Transformer/Native/Text/TextTransformations.cs b/NBi.Core/Transformation/Transformer/Native/Text/TextTransformations.cs index 5199d1064..98894919b 100644 --- a/NBi.Core/Transformation/Transformer/Native/Text/TextTransformations.cs +++ b/NBi.Core/Transformation/Transformer/Native/Text/TextTransformations.cs @@ -73,6 +73,29 @@ class TextToTrim : AbstractTextTransformation protected override object EvaluateBlank() => "(empty)"; protected override object EvaluateString(string value) => value.Trim(); } + abstract class AbstractTextAppend : AbstractTextTransformation + { + public IScalarResolver Append { get; } + public AbstractTextAppend(IScalarResolver append) + => Append = append; + + protected override object EvaluateEmpty() => Append.Execute(); + protected override object EvaluateBlank() => Append.Execute(); + } + + class TextToPrefix : AbstractTextAppend + { + public TextToPrefix(IScalarResolver prefix) + : base(prefix) { } + protected override object EvaluateString(string value) => $"{Append.Execute()}{value}"; + } + + class TextToSuffix : AbstractTextAppend + { + public TextToSuffix(IScalarResolver suffix) + : base(suffix) { } + protected override object EvaluateString(string value) => $"{value}{Append.Execute()}"; + } abstract class AbstractTextLengthTransformation : AbstractTextTransformation { diff --git a/NBi.Testing.Core/Transformation/Transformer/Native/TextTest.cs b/NBi.Testing.Core/Transformation/Transformer/Native/TextTest.cs index e5f7fe28f..249115551 100644 --- a/NBi.Testing.Core/Transformation/Transformer/Native/TextTest.cs +++ b/NBi.Testing.Core/Transformation/Transformer/Native/TextTest.cs @@ -232,6 +232,30 @@ public void Execute_TokenCount_Valid(object value, int expected) Assert.That(result, Is.EqualTo(expected)); } + [Test] + [TestCase("123456789", "abc", "abc123456789")] + [TestCase("(null)", "abc", "(null)")] + [TestCase("(empty)", "abc", "abc")] + [TestCase("(blank)", "abc", "abc")] + public void Execute_TextToPrefix_Valid(string value, string prefix, string expected) + { + var function = new TextToPrefix(new LiteralScalarResolver(prefix)); + var result = function.Evaluate(value); + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + [TestCase("123456789", "abc", "123456789abc")] + [TestCase("(null)", "abc", "(null)")] + [TestCase("(empty)", "abc", "abc")] + [TestCase("(blank)", "abc", "abc")] + public void Execute_TextToSuffix_Valid(string value, string suffix, string expected) + { + var function = new TextToSuffix(new LiteralScalarResolver(suffix)); + var result = function.Evaluate(value); + Assert.That(result, Is.EqualTo(expected)); + } + [Test] [TestCase("123456789", 9, "123456789")] [TestCase("123456789", 10, "123456789")] diff --git a/NBi.Testing.Core/Transformation/Transformer/NativeTransformationFactoryTest.cs b/NBi.Testing.Core/Transformation/Transformer/NativeTransformationFactoryTest.cs index 8e04fedf3..2fa1e4099 100644 --- a/NBi.Testing.Core/Transformation/Transformer/NativeTransformationFactoryTest.cs +++ b/NBi.Testing.Core/Transformation/Transformer/NativeTransformationFactoryTest.cs @@ -149,6 +149,8 @@ public void Instantiate_ExistingWithParametersAndVariables_CorrectType() [TestCase("text-to-trim")] [TestCase("text-to-upper")] [TestCase("text-to-lower")] + [TestCase("text-to-suffix(abc)")] + [TestCase("text-to-prefix(abc)")] [TestCase("text-to-length")] [TestCase("text-to-first-chars(3)")] [TestCase("text-to-last-chars(3)")] diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index fed7b831a..575041774 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -658,6 +658,8 @@ + + From a1aa9d90a30ded7eca6d3d4cb0d64d7627b43a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 11 Nov 2019 11:25:07 +0100 Subject: [PATCH 21/57] Implement the filter function on a sequence and add acceptance tests --- .../Calculation/Predicate/PredicateFactory.cs | 2 +- NBi.Core/NBi.Core.csproj | 2 + .../Resolver/FileLoopSequenceResolver.cs | 10 ++- .../Resolver/FileLoopSequenceResolverArgs.cs | 4 +- .../Resolver/FilterSequenceResolver.cs | 34 ++++++++++ .../Resolver/FilterSequenceResolverArgs.cs | 26 +++++++ .../Resolver/SequenceResolverFactory.cs | 3 +- .../Transformer/NativeTransformer.cs | 12 +++- .../Builder/Helper/InstanceArgsBuilder.cs | 41 +++++++++++- NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + .../Resolver/FilterSequenceResolverTest.cs | 67 +++++++++++++++++++ .../Resources/FileLoopXmlTestSuite.xml | 22 ++++++ .../Variables/Sequence/FileLoopXmlTest.cs | 13 ++++ .../Acceptance/Resources/Csv/MyEmpty.csv | 1 + .../Resources/Positive/MultipleInstance.nbits | 28 +++++++- .../Resolver/FileSequenceResolverTest.cs | 56 ++++++++++++---- NBi.Testing/NBi.Testing.csproj | 3 + NBi.Xml/Items/Calculation/PredicationXml.cs | 20 ++++-- NBi.Xml/NBi.Xml.csproj | 2 + NBi.Xml/Schema/BaseType.xsd | 13 +++- NBi.Xml/Variables/InstanceVariableXml.cs | 1 + .../Variables/Sequence/FilterSequenceXml.cs | 16 +++++ .../Sequence/PredicationSequenceXml.cs | 18 +++++ NBi.Xml/Variables/Sequence/SequenceXml.cs | 6 ++ 24 files changed, 361 insertions(+), 40 deletions(-) create mode 100644 NBi.Core/Sequence/Resolver/FilterSequenceResolver.cs create mode 100644 NBi.Core/Sequence/Resolver/FilterSequenceResolverArgs.cs create mode 100644 NBi.Testing.Core/Sequence/Resolver/FilterSequenceResolverTest.cs create mode 100644 NBi.Testing/Acceptance/Resources/Csv/MyEmpty.csv create mode 100644 NBi.Xml/Variables/Sequence/FilterSequenceXml.cs create mode 100644 NBi.Xml/Variables/Sequence/PredicationSequenceXml.cs diff --git a/NBi.Core/Calculation/Predicate/PredicateFactory.cs b/NBi.Core/Calculation/Predicate/PredicateFactory.cs index 292f0ad13..011b73828 100644 --- a/NBi.Core/Calculation/Predicate/PredicateFactory.cs +++ b/NBi.Core/Calculation/Predicate/PredicateFactory.cs @@ -14,7 +14,7 @@ namespace NBi.Core.Calculation.Predicate { - class PredicateFactory + public class PredicateFactory { private IPredicate Instantiate(ComparerType comparerType, ColumnType columnType, bool not, IResolver reference, string culture, StringComparison stringComparison, object secondOperand) { diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 2b48937d2..878731e10 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -714,7 +714,9 @@ + + diff --git a/NBi.Core/Sequence/Resolver/FileLoopSequenceResolver.cs b/NBi.Core/Sequence/Resolver/FileLoopSequenceResolver.cs index dbfad21cb..2853132b1 100644 --- a/NBi.Core/Sequence/Resolver/FileLoopSequenceResolver.cs +++ b/NBi.Core/Sequence/Resolver/FileLoopSequenceResolver.cs @@ -11,20 +11,18 @@ namespace NBi.Core.Sequence.Resolver { public class FileLoopSequenceResolver : ISequenceResolver { - private readonly FileLoopSequenceResolverArgs args; + protected FileLoopSequenceResolverArgs Args { get; } - public FileLoopSequenceResolver(FileLoopSequenceResolverArgs args) => this.args = args; + public FileLoopSequenceResolver(FileLoopSequenceResolverArgs args) => Args = args; object IResolver.Execute() => Execute(); IList ISequenceResolver.Execute() => Execute(); public List Execute() { - var fileLister = new FileLister(PathExtensions.CombineOrRoot(args.BasePath, args.Path)); - var files = fileLister.Execute(args.Filters); + var fileLister = new FileLister(PathExtensions.CombineOrRoot(Args.BasePath, Args.Path)); + var files = fileLister.Execute(Args.Filters); return files.Select(x => x.Name).ToList(); } - - } } diff --git a/NBi.Core/Sequence/Resolver/FileLoopSequenceResolverArgs.cs b/NBi.Core/Sequence/Resolver/FileLoopSequenceResolverArgs.cs index 826a2648a..ef61bbd06 100644 --- a/NBi.Core/Sequence/Resolver/FileLoopSequenceResolverArgs.cs +++ b/NBi.Core/Sequence/Resolver/FileLoopSequenceResolverArgs.cs @@ -11,8 +11,6 @@ public class FileLoopSequenceResolverArgs : ISequenceResolverArgs { public string BasePath { get; set; } public string Path { get; set; } - public IList Filters { get; set; } - - public FileLoopSequenceResolverArgs() => Filters = new List(); + public IList Filters { get; set; } = new List(); } } diff --git a/NBi.Core/Sequence/Resolver/FilterSequenceResolver.cs b/NBi.Core/Sequence/Resolver/FilterSequenceResolver.cs new file mode 100644 index 000000000..19e768307 --- /dev/null +++ b/NBi.Core/Sequence/Resolver/FilterSequenceResolver.cs @@ -0,0 +1,34 @@ +using Microsoft.CSharp; +using NBi.Core.Assemblies; +using NBi.Core.Scalar.Casting; +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Resolver +{ + public class FilterSequenceResolver : ISequenceResolver + { + private FilterSequenceResolverArgs Args { get; } + + public FilterSequenceResolver(FilterSequenceResolverArgs args) + => Args = args; + + public List Execute() + { + var candidates = Args.Resolver.Execute().Cast().ToList(); + var transfomedValues = Args.OperandTransformation == null ? candidates.Cast() : candidates.Select(c => Args.OperandTransformation.Execute(c)); + var zip = candidates.Zip(transfomedValues, (x, y) => new { Original = x, Transformed = y }); + return zip.Where(x => Args.Predicate.Execute(x.Transformed)).Select(x => x.Original).ToList(); + } + + IList ISequenceResolver.Execute() => Execute(); + + object IResolver.Execute() => Execute(); + } +} \ No newline at end of file diff --git a/NBi.Core/Sequence/Resolver/FilterSequenceResolverArgs.cs b/NBi.Core/Sequence/Resolver/FilterSequenceResolverArgs.cs new file mode 100644 index 000000000..e78a7e6b4 --- /dev/null +++ b/NBi.Core/Sequence/Resolver/FilterSequenceResolverArgs.cs @@ -0,0 +1,26 @@ +using NBi.Core.Assemblies; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Query; +using NBi.Core.Query.Resolver; +using NBi.Core.ResultSet.Resolver; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Transformation; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Resolver +{ + public class FilterSequenceResolverArgs : ISequenceResolverArgs + { + public ISequenceResolver Resolver { get; } + public ITransformer OperandTransformation { get; } + public IPredicate Predicate { get; } + + public FilterSequenceResolverArgs(ISequenceResolver resolver, IPredicate predicate, ITransformer transformation) + => (Resolver, Predicate, OperandTransformation) = (resolver, predicate, transformation); + } +} diff --git a/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs b/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs index a9fe3316b..20b474eba 100644 --- a/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs +++ b/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs @@ -26,9 +26,10 @@ internal ISequenceResolver Instantiate(ISequenceResolverArgs args) case FileLoopSequenceResolverArgs fileArgs: return (ISequenceResolver)new FileLoopSequenceResolver(fileArgs); case ILoopSequenceResolverArgs loopArgs: { - var strategy = MapStrategy(args as ILoopSequenceResolverArgs); + var strategy = MapStrategy(loopArgs); return new LoopSequenceResolver(strategy); } + case FilterSequenceResolverArgs filterArgs: return new FilterSequenceResolver(filterArgs); default: throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a Scalar"); } diff --git a/NBi.Core/Transformation/Transformer/NativeTransformer.cs b/NBi.Core/Transformation/Transformer/NativeTransformer.cs index bbdb0b96c..282545546 100644 --- a/NBi.Core/Transformation/Transformer/NativeTransformer.cs +++ b/NBi.Core/Transformation/Transformer/NativeTransformer.cs @@ -22,10 +22,17 @@ class NativeTransformer : ITransformer private IList Transformations { get; } = new List(); private bool IsInitialized { get; set; } = false; - + public NativeTransformer(ServiceLocator serviceLocator, Context context) => (ServiceLocator, Context) = (serviceLocator, context); + public NativeTransformer(ServiceLocator serviceLocator, Context context, INativeTransformation transformation) + :this (serviceLocator, context) + { + Transformations.Add(transformation); + IsInitialized = true; + } + public void Initialize(string code) { var functions = code.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); @@ -48,7 +55,7 @@ public object Execute(object value) object typedValue; if (value == null || value == DBNull.Value || value as string == "(null)") typedValue = null; - else if ((typeof(T)!=typeof(string)) && (value is string) && ((string.IsNullOrEmpty(value as string) || value as string == "(empty)"))) + else if ((typeof(T) != typeof(string)) && (value is string) && ((string.IsNullOrEmpty(value as string) || value as string == "(empty)"))) typedValue = null; else typedValue = caster.Execute(value); @@ -60,5 +67,6 @@ public object Execute(object value) return transformedValue; } + } } diff --git a/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs b/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs index cc65a0c51..549abd8a3 100644 --- a/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs @@ -1,12 +1,15 @@ -using NBi.Core.Injection; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Injection; using NBi.Core.ResultSet; using NBi.Core.Sequence.Resolver; using NBi.Core.Transformation; +using NBi.Core.Transformation.Transformer; using NBi.Core.Variable; using NBi.Core.Variable.Instantiation; using NBi.Xml; using NBi.Xml.Settings; using NBi.Xml.Variables; +using NBi.Xml.Variables.Sequence; using System; using System.Collections.Generic; using System.Linq; @@ -67,13 +70,15 @@ public void Build() argsBuilder.Build(); var factory = new SequenceResolverFactory(ServiceLocator); + var innerResolver = factory.Instantiate(variable.Type, argsBuilder.GetArgs()); + var sequenceResolver = BuildFilterSequenceResolver(variable.Type, innerResolver, variable.Filter); if (((obj as InstanceSettlingXml).DerivedVariables?.Count() ?? 0) == 0) { args = new SingleVariableInstanceArgs() { Name = variable.Name, - Resolver = factory.Instantiate(variable.Type, argsBuilder.GetArgs()), + Resolver = sequenceResolver, Categories = (obj as InstanceSettlingXml).Categories, Traits = (obj as InstanceSettlingXml).Traits.ToDictionary(x => x.Name, x => x.Value), }; @@ -93,7 +98,7 @@ public void Build() args = new DerivedVariableInstanceArgs() { Name = variable.Name, - Resolver = factory.Instantiate(variable.Type, argsBuilder.GetArgs()), + Resolver = sequenceResolver, Derivations = derivationArgs, Categories = (obj as InstanceSettlingXml).Categories, Traits = (obj as InstanceSettlingXml).Traits.ToDictionary(x => x.Name, x => x.Value), @@ -102,6 +107,36 @@ public void Build() } } + private ISequenceResolver BuildFilterSequenceResolver(ColumnType type, ISequenceResolver resolver, FilterSequenceXml filterXml) + { + if (filterXml == null) + return resolver; + + var predicateBuilder = new PredicateArgsBuilder(ServiceLocator, new Context(Variables)); + var predicateArgs = predicateBuilder.Execute(filterXml.Predication.ColumnType, filterXml.Predication.Predicate); + var predicate = new PredicateFactory().Instantiate(predicateArgs); + + var operandTransformation = new TransformerFactory(ServiceLocator, new Context(Variables)).Instantiate + ( + new OperandTransformation + { + OriginalType = type, + Code = filterXml.Predication.Operand + } + ); + operandTransformation.Initialize(filterXml.Predication.Operand); + + var factory = new SequenceResolverFactory(ServiceLocator); + return factory.Instantiate(type, new FilterSequenceResolverArgs(resolver, predicate, operandTransformation)); + } + + private class OperandTransformation : ITransformationInfo + { + public ColumnType OriginalType { get ; set; } + public LanguageType Language { get => LanguageType.Native; set => throw new NotImplementedException(); } + public string Code { get; set; } + } + public IInstanceArgs GetArgs() => args ?? throw new InvalidOperationException(); private class TransformaterArgs : ITransformationInfo diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 8ca518e3a..c76983a3f 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -230,6 +230,7 @@ + diff --git a/NBi.Testing.Core/Sequence/Resolver/FilterSequenceResolverTest.cs b/NBi.Testing.Core/Sequence/Resolver/FilterSequenceResolverTest.cs new file mode 100644 index 000000000..fe9dfdde7 --- /dev/null +++ b/NBi.Testing.Core/Sequence/Resolver/FilterSequenceResolverTest.cs @@ -0,0 +1,67 @@ +using NBi.Core.Calculation.Predicate.DateTime; +using NBi.Core.Calculation.Predicate.Numeric; +using NBi.Core.Injection; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using NBi.Core.Transformation.Transformer; +using NBi.Core.Transformation.Transformer.Native; +using NBi.Core.Variable; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Sequence.Resolver +{ + [TestFixture] + public class FilterSequenceResolverTest + { + [Test] + public void Execute_Numeric_TwoElements() + { + var resolvers = new List() + { + new LiteralScalarResolver(10), + new LiteralScalarResolver(11), + new LiteralScalarResolver(12), + new LiteralScalarResolver(13), + }; + var innerArgs = new ListSequenceResolverArgs(resolvers); + var innerResolver = new ListSequenceResolver(innerArgs); + var predicate = new NumericModulo(false, 2, new LiteralScalarResolver(0)); + var args = new FilterSequenceResolverArgs(innerResolver, predicate, null); + + var resolver = new FilterSequenceResolver(args); + var elements = resolver.Execute(); + Assert.That(elements.Count(), Is.EqualTo(2)); + Assert.That(elements, Has.Member(10)); + Assert.That(elements, Has.Member(12)); + } + + [Test] + public void Execute_DateTime_TwoElements() + { + var resolvers = new List() + { + new LiteralScalarResolver("2014-01-01"), + new LiteralScalarResolver("2015-01-01"), + new LiteralScalarResolver("2016-01-01"), + new LiteralScalarResolver("2017-01-01"), + }; + var innerArgs = new ListSequenceResolverArgs(resolvers); + var innerResolver = new ListSequenceResolver(innerArgs); + var predicate = new DateTimeMoreThan(false, new LiteralScalarResolver("2015-06-01")); + var transformation = new NativeTransformer(new ServiceLocator(), null, new DateTimeToNextYear()); + var args = new FilterSequenceResolverArgs(innerResolver, predicate, transformation); + + var resolver = new FilterSequenceResolver(args); + var elements = resolver.Execute(); + Assert.That(elements.Count(), Is.EqualTo(3)); + Assert.That(elements, Has.Member(new DateTime(2015, 1, 1))); + Assert.That(elements, Has.Member(new DateTime(2016, 1, 1))); + Assert.That(elements, Has.Member(new DateTime(2017, 1, 1))); + } + } +} diff --git a/NBi.Testing.Xml/Resources/FileLoopXmlTestSuite.xml b/NBi.Testing.Xml/Resources/FileLoopXmlTestSuite.xml index 76f0d8408..fa97f03b4 100644 --- a/NBi.Testing.Xml/Resources/FileLoopXmlTestSuite.xml +++ b/NBi.Testing.Xml/Resources/FileLoopXmlTestSuite.xml @@ -22,4 +22,26 @@ + + + + + + + 5000 + + + + + + + + + + + + + + + diff --git a/NBi.Testing.Xml/Variables/Sequence/FileLoopXmlTest.cs b/NBi.Testing.Xml/Variables/Sequence/FileLoopXmlTest.cs index 3edcfab22..8296ffc12 100644 --- a/NBi.Testing.Xml/Variables/Sequence/FileLoopXmlTest.cs +++ b/NBi.Testing.Xml/Variables/Sequence/FileLoopXmlTest.cs @@ -13,6 +13,7 @@ using System.Reflection; using NBi.Core.ResultSet; using NBi.Xml.Variables.Sequence; +using NBi.Core.Calculation; namespace NBi.Testing.Xml.Unit.Variables.Sequence { @@ -41,6 +42,18 @@ public void Deserialize_SampleFile_VariableHasCorrectNameAndType() Assert.That(variable.FileLoop.Pattern, Is.EqualTo("foo-*.txt")); } + + [Test] + public void Deserialize_SampleFile_FilterCorrectly() + { + TestSuiteXml ts = DeserializeSample(); + var localVariable = ts.Tests[1].InstanceSettling.Variable as InstanceVariableXml; + + // Check the properties of the object. + Assert.That(localVariable.Filter.Predication.Operand, Is.EqualTo(@"value | file-to-size(C:\Temp\)")); + Assert.That(localVariable.Filter.Predication.Predicate.ComparerType, Is.EqualTo(ComparerType.MoreThan)); + } + [Test] public void Serialize_Variable_FileLoopCorrectlySerialized() { diff --git a/NBi.Testing/Acceptance/Resources/Csv/MyEmpty.csv b/NBi.Testing/Acceptance/Resources/Csv/MyEmpty.csv new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/NBi.Testing/Acceptance/Resources/Csv/MyEmpty.csv @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits index f112b2793..04d8345d0 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits @@ -10,7 +10,7 @@ - + - + + + + + + + + 8 + + + + + + + + + + + + + + diff --git a/NBi.Testing/Integration/Core/Sequence/Resolver/FileSequenceResolverTest.cs b/NBi.Testing/Integration/Core/Sequence/Resolver/FileSequenceResolverTest.cs index 111a7cef6..ecec541d2 100644 --- a/NBi.Testing/Integration/Core/Sequence/Resolver/FileSequenceResolverTest.cs +++ b/NBi.Testing/Integration/Core/Sequence/Resolver/FileSequenceResolverTest.cs @@ -2,6 +2,8 @@ using NBi.Core.IO.Filtering; using NBi.Core.Scalar.Resolver; using NBi.Core.Sequence.Resolver; +using NBi.Core.Transformation.Transformer; +using NBi.Core.Transformation.Transformer.Native.IO; using NUnit.Framework; using System; using System.Collections.Generic; @@ -33,34 +35,62 @@ public void Cleanup() } [Test] - public void Execute_PatternCreation_CorrectCount() + public void Execute_Pattern_CorrectCount() { var files = new[] { "bar-0.txt", "foo-0.txt", "foo-1.txt", "foo-01.txt", "foo-0.csv" }; foreach (var file in files) File.AppendAllText(Path.Combine(DirectoryName, file), "."); - File.SetCreationTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-3)); - File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-1)); - File.SetCreationTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); - File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); - var resolver = new FileLoopSequenceResolver ( new FileLoopSequenceResolverArgs() { Path = DirectoryName, - Filters = new List() - { - new PatternRootFilter("foo-*.txt"), - new CreationDateTimeFilter(new DateTimeMoreThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(-2))), false), - } + Filters = new List { new PatternRootFilter("foo-*.txt") }, } ); + var result = resolver.Execute(); + Assert.That(result.Count(), Is.EqualTo(3)); + Assert.That(result, Has.Member($"foo-01.txt")); + Assert.That(result, Has.Member($"foo-1.txt")); + Assert.That(result, Has.Member($"foo-0.txt")); + } + + + [Test] + public void Execute_PatternWithCreationFilter_CorrectCount() + { + var files = new[] { "bar-0.txt", "foo-0.txt", "foo-1.txt", "foo-01.txt", "foo-0.csv" }; + foreach (var file in files) + File.AppendAllText(Path.Combine(DirectoryName, file), "."); + + File.SetCreationTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-3)); + File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-1)); + File.SetCreationTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); + File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); + + var resolver = new FilterSequenceResolver + ( + new FilterSequenceResolverArgs + ( + new FileLoopSequenceResolver + ( + new FileLoopSequenceResolverArgs() + { + Path = DirectoryName, + Filters = new List { new PatternRootFilter("foo-*.txt") }, + } + ), + new DateTimeMoreThanOrEqual(false, new LiteralScalarResolver(DateTime.Now.AddDays(-2))), + new NativeTransformer(null, null, new FileToCreationDateTime(DirectoryName)) + ) + ); + var result = resolver.Execute(); Assert.That(result.Count(), Is.EqualTo(2)); - Assert.That(result, Has.Member("foo-01.txt")); - Assert.That(result, Has.Member("foo-1.txt")); + Assert.That(result, Has.Member($"foo-01.txt")); + Assert.That(result, Has.Member($"foo-1.txt")); } } } diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 1c5dcf7a1..668bdefc9 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -523,6 +523,9 @@ Always + + Always + Always diff --git a/NBi.Xml/Items/Calculation/PredicationXml.cs b/NBi.Xml/Items/Calculation/PredicationXml.cs index efdcd9525..66122b4e4 100644 --- a/NBi.Xml/Items/Calculation/PredicationXml.cs +++ b/NBi.Xml/Items/Calculation/PredicationXml.cs @@ -13,13 +13,8 @@ namespace NBi.Xml.Items.Calculation { - public class PredicationXml + public class PredicationXml : BasePredicationXml { - public PredicationXml() - { - ColumnType = ColumnType.Numeric; - } - [XmlIgnore()] [XmlAttribute("column-index")] [Obsolete("Deprecated. Use operand in place of column-index")] @@ -43,11 +38,21 @@ public string OperandSerialized [XmlIgnore()] public string Name { get => Operand.Label; set => Operand=new ColumnIdentifierFactory().Instantiate(value); } + + } + + public abstract class BasePredicationXml + { + public BasePredicationXml() + { + ColumnType = ColumnType.Numeric; + } + [DefaultValue(ColumnType.Numeric)] [XmlAttribute("type")] public ColumnType ColumnType { get; set; } - [XmlElement(Type = typeof(LessThanXml), ElementName ="less-than")] + [XmlElement(Type = typeof(LessThanXml), ElementName = "less-than")] [XmlElement(Type = typeof(MoreThanXml), ElementName = "more-than")] [XmlElement(Type = typeof(EqualXml), ElementName = "equal")] [XmlElement(Type = typeof(NullXml), ElementName = "null")] @@ -72,4 +77,5 @@ public string OperandSerialized [XmlElement(Type = typeof(FalseXml), ElementName = "false")] public PredicateXml Predicate { get; set; } } + } diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 10a776674..156259326 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -323,6 +323,8 @@ + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 575041774..24db9a51e 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1297,7 +1297,11 @@ - + + + + + @@ -1405,6 +1409,13 @@ + + + + + + + diff --git a/NBi.Xml/Variables/InstanceVariableXml.cs b/NBi.Xml/Variables/InstanceVariableXml.cs index 3420af5ce..f8eb5a511 100644 --- a/NBi.Xml/Variables/InstanceVariableXml.cs +++ b/NBi.Xml/Variables/InstanceVariableXml.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Xml.Items.Calculation; using NBi.Xml.Variables.Sequence; using System; using System.Collections.Generic; diff --git a/NBi.Xml/Variables/Sequence/FilterSequenceXml.cs b/NBi.Xml/Variables/Sequence/FilterSequenceXml.cs new file mode 100644 index 000000000..42a1540dc --- /dev/null +++ b/NBi.Xml/Variables/Sequence/FilterSequenceXml.cs @@ -0,0 +1,16 @@ +using NBi.Xml.Items.Calculation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Variables.Sequence +{ + public class FilterSequenceXml + { + [XmlElement("predicate")] + public PredicationSequenceXml Predication { get; set; } + } +} diff --git a/NBi.Xml/Variables/Sequence/PredicationSequenceXml.cs b/NBi.Xml/Variables/Sequence/PredicationSequenceXml.cs new file mode 100644 index 000000000..5a7459dac --- /dev/null +++ b/NBi.Xml/Variables/Sequence/PredicationSequenceXml.cs @@ -0,0 +1,18 @@ +using NBi.Core.ResultSet; +using NBi.Xml.Items.Calculation; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Variables.Sequence +{ + public class PredicationSequenceXml : BasePredicationXml + { + [XmlAttribute("operand")] + public string Operand { get; set; } + } +} diff --git a/NBi.Xml/Variables/Sequence/SequenceXml.cs b/NBi.Xml/Variables/Sequence/SequenceXml.cs index bc93894c6..1b531a2cf 100644 --- a/NBi.Xml/Variables/Sequence/SequenceXml.cs +++ b/NBi.Xml/Variables/Sequence/SequenceXml.cs @@ -31,5 +31,11 @@ public class SequenceXml [XmlIgnore] public bool ItemsSpecified { get => Items.Count > 0; set { } } + + [XmlElement("filter")] + public FilterSequenceXml Filter { get; set; } = null; + + [XmlIgnore] + public bool FilterSpecified { get => Filter != null; set { } } } } From 375299545c0a4468cfc5acffce82a3f45a75c255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 11 Nov 2019 11:44:39 +0100 Subject: [PATCH 22/57] Remove old implementation of filters for loop-file in NBi.Core.IO --- NBi.Core/IO/FileLister.cs | 2 -- .../IO/Filtering/CreationDateTimeFilter.cs | 28 ------------------- NBi.Core/IO/Filtering/IPropertyFilter.cs | 14 ---------- NBi.Core/IO/Filtering/SizeFilter.cs | 20 ------------- NBi.Core/IO/Filtering/UpdateDateTimeFilter.cs | 28 ------------------- NBi.Core/NBi.Core.csproj | 4 --- 6 files changed, 96 deletions(-) delete mode 100644 NBi.Core/IO/Filtering/CreationDateTimeFilter.cs delete mode 100644 NBi.Core/IO/Filtering/IPropertyFilter.cs delete mode 100644 NBi.Core/IO/Filtering/SizeFilter.cs delete mode 100644 NBi.Core/IO/Filtering/UpdateDateTimeFilter.cs diff --git a/NBi.Core/IO/FileLister.cs b/NBi.Core/IO/FileLister.cs index 09f9f3103..5ae4cab09 100644 --- a/NBi.Core/IO/FileLister.cs +++ b/NBi.Core/IO/FileLister.cs @@ -18,8 +18,6 @@ public IEnumerable Execute(IEnumerable filters) { var rootFilter = filters.OfType().SingleOrDefault() ?? new NullRootFilter(); IEnumerable files = rootFilter.Execute(Path); - foreach (var propertyFilter in filters.OfType()) - files = files.Where(x => propertyFilter.Execute(x)); return files; } } diff --git a/NBi.Core/IO/Filtering/CreationDateTimeFilter.cs b/NBi.Core/IO/Filtering/CreationDateTimeFilter.cs deleted file mode 100644 index d2a27de86..000000000 --- a/NBi.Core/IO/Filtering/CreationDateTimeFilter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.IO.Filtering -{ - class CreationDateTimeFilter : IPropertyFilter - { - private readonly IPredicate predicate; - private readonly Func execute; - - public CreationDateTimeFilter(IPredicate predicate, bool isUtc) - { - this.predicate = predicate; - if (isUtc) - execute = (FileInfo fileInfo) => predicate.Execute(fileInfo.CreationTimeUtc); - else - execute = (FileInfo fileInfo) => predicate.Execute(fileInfo.CreationTime); - } - - public bool Execute(FileInfo fileInfo) - => predicate.Execute(fileInfo.CreationTimeUtc); - } -} diff --git a/NBi.Core/IO/Filtering/IPropertyFilter.cs b/NBi.Core/IO/Filtering/IPropertyFilter.cs deleted file mode 100644 index 1c167d27a..000000000 --- a/NBi.Core/IO/Filtering/IPropertyFilter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.IO.Filtering -{ - public interface IPropertyFilter : IFileFilter - { - bool Execute(FileInfo fileInfo); - } -} diff --git a/NBi.Core/IO/Filtering/SizeFilter.cs b/NBi.Core/IO/Filtering/SizeFilter.cs deleted file mode 100644 index e8360062e..000000000 --- a/NBi.Core/IO/Filtering/SizeFilter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.IO.Filtering -{ - class SizeFilter : IPropertyFilter - { - private readonly IPredicate predicate; - - public SizeFilter(IPredicate predicate) => this.predicate = predicate; - - public bool Execute(FileInfo fileInfo) - => predicate.Execute(fileInfo.Length); - } -} diff --git a/NBi.Core/IO/Filtering/UpdateDateTimeFilter.cs b/NBi.Core/IO/Filtering/UpdateDateTimeFilter.cs deleted file mode 100644 index 19ea7ff63..000000000 --- a/NBi.Core/IO/Filtering/UpdateDateTimeFilter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.IO.Filtering -{ - class UpdateDateTimeFilter : IPropertyFilter - { - private readonly IPredicate predicate; - private readonly Func execute; - - public UpdateDateTimeFilter(IPredicate predicate, bool isUtc) - { - this.predicate = predicate; - if (isUtc) - execute = (FileInfo fileInfo) => predicate.Execute(fileInfo.LastWriteTimeUtc); - else - execute = (FileInfo fileInfo) => predicate.Execute(fileInfo.LastWriteTime); - } - - public bool Execute(FileInfo fileInfo) => execute.Invoke(fileInfo); - - } -} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 878731e10..c63d2b1fe 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -720,14 +720,10 @@ - - - - From 1f146820497d16365d7a12b677f8af1182387763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 11 Nov 2019 11:54:27 +0100 Subject: [PATCH 23/57] Add some addition cleaning --- .../Integration/Core/IO/FileListerTest.cs | 9 +-- .../Filtering/CreationDateTimeFilterTest.cs | 59 ------------------ .../Core/IO/Filtering/SizeFilterTest.cs | 60 ------------------- .../IO/Filtering/UpdateDateTimeFilterTest.cs | 59 ------------------ NBi.Testing/NBi.Testing.csproj | 3 - 5 files changed, 1 insertion(+), 189 deletions(-) delete mode 100644 NBi.Testing/Integration/Core/IO/Filtering/CreationDateTimeFilterTest.cs delete mode 100644 NBi.Testing/Integration/Core/IO/Filtering/SizeFilterTest.cs delete mode 100644 NBi.Testing/Integration/Core/IO/Filtering/UpdateDateTimeFilterTest.cs diff --git a/NBi.Testing/Integration/Core/IO/FileListerTest.cs b/NBi.Testing/Integration/Core/IO/FileListerTest.cs index 246eb032e..eb9bdc6db 100644 --- a/NBi.Testing/Integration/Core/IO/FileListerTest.cs +++ b/NBi.Testing/Integration/Core/IO/FileListerTest.cs @@ -39,21 +39,14 @@ public void Execute_PatternCreationUpdate_CorrectCount() foreach (var file in files) File.AppendAllText(Path.Combine(DirectoryName, file), "."); - File.SetCreationTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-3)); - File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-0.txt"), DateTime.Now.AddDays(-1)); - File.SetCreationTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); - File.SetLastWriteTime(Path.Combine(DirectoryName, "foo-01.txt"), DateTime.Now.AddDays(-1)); - var fileLister = new FileLister(DirectoryName); var filters = new List() { new PatternRootFilter("foo-*.txt"), - new CreationDateTimeFilter(new DateTimeMoreThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(-2))), false), - new UpdateDateTimeFilter(new DateTimeMoreThan(false, new LiteralScalarResolver(DateTime.Now.AddHours(-1))), false), }; var dir = new DirectoryInfo(DirectoryName); - Assert.That(fileLister.Execute(filters).Count(), Is.EqualTo(1)); + Assert.That(fileLister.Execute(filters).Count(), Is.EqualTo(3)); } } } diff --git a/NBi.Testing/Integration/Core/IO/Filtering/CreationDateTimeFilterTest.cs b/NBi.Testing/Integration/Core/IO/Filtering/CreationDateTimeFilterTest.cs deleted file mode 100644 index 0e6a6841b..000000000 --- a/NBi.Testing/Integration/Core/IO/Filtering/CreationDateTimeFilterTest.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Moq; -using NBi.Core.Calculation.Predicate.DateTime; -using NBi.Core.IO.Filtering; -using NBi.Core.Scalar.Resolver; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Testing.Integration.Core.IO.Filtering -{ - public class CreationDateTimeFilterTest - { - private string DirectoryName { get => $@"Temp\{GetType().Name}\"; } - - [SetUp] - public void Setup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - Directory.CreateDirectory(DirectoryName); - - } - - [TearDown] - public void Cleanup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - } - - [Test] - [TestCase(1, false)] - [TestCase(-1, true)] - public void Execute_MoreThan_Correct(int shift, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new CreationDateTimeFilter(new DateTimeMoreThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(shift))), false); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - - [Test] - [TestCase(-1, false)] - [TestCase(1, true)] - public void Execute_LessThan_Correct(int shift, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new CreationDateTimeFilter(new DateTimeLessThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(shift))), false); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - } -} diff --git a/NBi.Testing/Integration/Core/IO/Filtering/SizeFilterTest.cs b/NBi.Testing/Integration/Core/IO/Filtering/SizeFilterTest.cs deleted file mode 100644 index 620a9e193..000000000 --- a/NBi.Testing/Integration/Core/IO/Filtering/SizeFilterTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Moq; -using NBi.Core.Calculation.Predicate.DateTime; -using NBi.Core.Calculation.Predicate.Numeric; -using NBi.Core.IO.Filtering; -using NBi.Core.Scalar.Resolver; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Testing.Integration.Core.IO.Filtering -{ - public class SizeFilterTest - { - private string DirectoryName { get => $@"Temp\{GetType().Name}\"; } - - [SetUp] - public void Setup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - Directory.CreateDirectory(DirectoryName); - - } - - [TearDown] - public void Cleanup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - } - - [Test] - [TestCase(100, false)] - [TestCase(0, true)] - public void Execute_MoreThan_Correct(int size, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new SizeFilter(new NumericMoreThan(false, new LiteralScalarResolver(size))); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - - [Test] - [TestCase(100, true)] - [TestCase(0, false)] - public void Execute_LessThan_Correct(int size, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new SizeFilter(new NumericLessThan(false, new LiteralScalarResolver(size))); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - } -} diff --git a/NBi.Testing/Integration/Core/IO/Filtering/UpdateDateTimeFilterTest.cs b/NBi.Testing/Integration/Core/IO/Filtering/UpdateDateTimeFilterTest.cs deleted file mode 100644 index b7fbd3c5f..000000000 --- a/NBi.Testing/Integration/Core/IO/Filtering/UpdateDateTimeFilterTest.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Moq; -using NBi.Core.Calculation.Predicate.DateTime; -using NBi.Core.IO.Filtering; -using NBi.Core.Scalar.Resolver; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Testing.Integration.Core.IO.Filtering -{ - public class UpdateDateTimeFilterTest - { - private string DirectoryName { get => $@"Temp\{GetType().Name}\"; } - - [SetUp] - public void Setup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - Directory.CreateDirectory(DirectoryName); - - } - - [TearDown] - public void Cleanup() - { - if (Directory.Exists(DirectoryName)) - Directory.Delete(DirectoryName, true); - } - - [Test] - [TestCase(1, false)] - [TestCase(-1, true)] - public void Execute_MoreThan_Correct(int shift, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new UpdateDateTimeFilter(new DateTimeMoreThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(shift))), false); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - - [Test] - [TestCase(-1, false)] - [TestCase(1, true)] - public void Execute_LessThan_Correct(int shift, bool result) - { - File.AppendAllText(Path.Combine(DirectoryName, "foo.txt"), "."); - var fileInfo = new FileInfo(Path.Combine(DirectoryName, "foo.txt")); - var filter = new UpdateDateTimeFilter(new DateTimeLessThan(false, new LiteralScalarResolver(DateTime.Now.AddDays(shift))), false); - - Assert.That(filter.Execute(fileInfo), Is.EqualTo(result)); - } - } -} diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 668bdefc9..75d51231f 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -152,9 +152,6 @@ - - - From 76f1e8900fc3b82ff424f2361ed202b70473d941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Thu, 14 Nov 2019 00:11:20 +0100 Subject: [PATCH 24/57] Huge refactoring for IResultSetFilter including usage of Context for aliases and expressions --- NBi.Core/Calculation/BaseRankingFilter.cs | 20 +- .../AndCombinationPredicateFilter.cs | 35 -- .../BaseCombinationPredicateFilter.cs | 43 --- .../OrCombinationPredicateFilter.cs | 35 -- .../XOrCombinationPredicateFilter.cs | 34 -- NBi.Core/Calculation/FilterGroupByFilter.cs | 47 --- .../Grouping/CaseBased/GroupByCase.cs | 42 +++ .../AbstractByColumnGrouping.cs | 9 +- .../{ => ColumnBased}/NameByColumnGrouping.cs | 2 +- .../OrdinalByColumnGrouping.cs | 2 +- ...mnGroupingFactory.cs => GroupByFactory.cs} | 9 +- .../{IByColumnGrouping.cs => IGroupBy.cs} | 2 +- NBi.Core/Calculation/Grouping/NoneGrouping.cs | 4 +- .../Predication/AndCombinationPredication.cs | 28 ++ .../Predication/BaseCombinationPredication.cs | 51 +++ .../Calculation/Predication/IPredication.cs | 16 + .../Predication/OrCombinationPredication.cs | 30 ++ .../Predication/PredicationFactory.cs | 32 ++ .../Predication/SinglePredication.cs | 37 +++ .../Predication/XOrCombinationPredication.cs | 31 ++ .../Calculation/Ranking/AbstractRanking.cs | 4 +- .../Calculation/ResultSetFilterFactory.cs | 78 ----- ...redicateFilter.cs => RowValueExtractor.cs} | 67 +--- NBi.Core/Calculation/SinglePredicateFilter.cs | 74 +++-- NBi.Core/NBi.Core.csproj | 37 ++- .../Alteration/Reshaping/UnstackEngine.cs | 2 +- .../Summarization/SummarizeEngine.cs | 2 +- NBi.Core/ResultSet/Filtering/BaseFilter.cs | 56 ++++ NBi.Core/ResultSet/Filtering/GroupByFilter.cs | 41 +++ .../Filtering}/IResultSetFilter.cs | 10 +- .../Filtering}/NoneFilter.cs | 16 +- .../ResultSet/Filtering/PredicationFilter.cs | 25 ++ .../Filtering}/ResultSetFilter.cs | 2 +- .../Filtering/ResultSetFilterFactory.cs | 76 +++++ .../KeyCollectionEqualityComparer.cs | 16 + NBi.Core/Variable/Context.cs | 18 +- .../Builder/Helper/ResultSetSystemHelper.cs | 13 +- NBi.NUnit/Builder/ResultSetNoRowsBuilder.cs | 19 +- NBi.NUnit/Builder/ResultSetRowCountBuilder.cs | 15 +- NBi.NUnit/Query/AllRowsConstraint.cs | 1 + NBi.NUnit/Query/NoRowsConstraint.cs | 1 + NBi.NUnit/Query/RowCountFilterConstraint.cs | 4 +- .../RowCountFilterPercentageConstraint.cs | 1 + NBi.NUnit/Query/SingleRowConstraint.cs | 1 + NBi.NUnit/Query/SomeRowsConstraint.cs | 1 + .../NameByColumnGroupingTest.cs | 3 +- .../OrdinalByColumnGroupingTest.cs | 3 +- .../CultureSensitivePredicateMatchesTest.cs | 2 +- .../AndCombinationPredicationTest.cs | 94 ++++++ .../OrCombinationPredicationTest.cs | 112 +++++++ .../XOrCombinationPredicationTest.cs | 109 +++++++ .../Calculation/Ranking/BottomRankingTest.cs | 1 + .../Calculation/Ranking/TopRankingTest.cs | 1 + .../Calculation/SinglePredicateFilterTest.cs | 303 ------------------ NBi.Testing.Core/NBi.Testing.Core.csproj | 14 +- .../Filtering/GroupByFilterTest.cs} | 11 +- .../Filtering/PredicationFilterTest.cs} | 29 +- .../Resolver/ContextScalarResolverTest.cs | 6 +- .../Resolver/ScalarResolverFactoryTest.cs | 2 +- .../TransformationProviderTest.cs | 12 +- .../Helper/PredicateArgsBuilderTest.cs | 2 +- .../Helper/ScalarResolverArgsBuilderTest.cs | 6 +- .../AllRowsConstraintTest.cs | 38 +-- .../NoRowsConstraintTest.cs | 40 +-- .../SingleRowConstraintTest.cs | 40 +-- .../SomeRowsConstraintTest.cs | 46 ++- 66 files changed, 1067 insertions(+), 896 deletions(-) delete mode 100644 NBi.Core/Calculation/Combination/AndCombinationPredicateFilter.cs delete mode 100644 NBi.Core/Calculation/Combination/BaseCombinationPredicateFilter.cs delete mode 100644 NBi.Core/Calculation/Combination/OrCombinationPredicateFilter.cs delete mode 100644 NBi.Core/Calculation/Combination/XOrCombinationPredicateFilter.cs delete mode 100644 NBi.Core/Calculation/FilterGroupByFilter.cs create mode 100644 NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs rename NBi.Core/Calculation/Grouping/{ => ColumnBased}/AbstractByColumnGrouping.cs (77%) rename NBi.Core/Calculation/Grouping/{ => ColumnBased}/NameByColumnGrouping.cs (91%) rename NBi.Core/Calculation/Grouping/{ => ColumnBased}/OrdinalByColumnGrouping.cs (92%) rename NBi.Core/Calculation/Grouping/{ByColumnGroupingFactory.cs => GroupByFactory.cs} (90%) rename NBi.Core/Calculation/Grouping/{IByColumnGrouping.cs => IGroupBy.cs} (88%) create mode 100644 NBi.Core/Calculation/Predication/AndCombinationPredication.cs create mode 100644 NBi.Core/Calculation/Predication/BaseCombinationPredication.cs create mode 100644 NBi.Core/Calculation/Predication/IPredication.cs create mode 100644 NBi.Core/Calculation/Predication/OrCombinationPredication.cs create mode 100644 NBi.Core/Calculation/Predication/PredicationFactory.cs create mode 100644 NBi.Core/Calculation/Predication/SinglePredication.cs create mode 100644 NBi.Core/Calculation/Predication/XOrCombinationPredication.cs delete mode 100644 NBi.Core/Calculation/ResultSetFilterFactory.cs rename NBi.Core/Calculation/{BasePredicateFilter.cs => RowValueExtractor.cs} (60%) create mode 100644 NBi.Core/ResultSet/Filtering/BaseFilter.cs create mode 100644 NBi.Core/ResultSet/Filtering/GroupByFilter.cs rename NBi.Core/{Calculation => ResultSet/Filtering}/IResultSetFilter.cs (51%) rename NBi.Core/{Calculation => ResultSet/Filtering}/NoneFilter.cs (60%) create mode 100644 NBi.Core/ResultSet/Filtering/PredicationFilter.cs rename NBi.Core/{Calculation => ResultSet/Filtering}/ResultSetFilter.cs (86%) create mode 100644 NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs create mode 100644 NBi.Core/ResultSet/KeyCollectionEqualityComparer.cs rename NBi.Testing.Core/Calculation/Grouping/{ => ColumnBased}/NameByColumnGroupingTest.cs (97%) rename NBi.Testing.Core/Calculation/Grouping/{ => ColumnBased}/OrdinalByColumnGroupingTest.cs (97%) rename NBi.Testing.Core/Calculation/{ => Predicate}/CultureSensitivePredicateMatchesTest.cs (98%) create mode 100644 NBi.Testing.Core/Calculation/Predication/AndCombinationPredicationTest.cs create mode 100644 NBi.Testing.Core/Calculation/Predication/OrCombinationPredicationTest.cs create mode 100644 NBi.Testing.Core/Calculation/Predication/XOrCombinationPredicationTest.cs delete mode 100644 NBi.Testing.Core/Calculation/SinglePredicateFilterTest.cs rename NBi.Testing.Core/{Calculation/FilterGroupByFilterTest.cs => ResultSet/Filtering/GroupByFilterTest.cs} (87%) rename NBi.Testing.Core/{Calculation/CombinationPredicateFilterTest.cs => ResultSet/Filtering/PredicationFilterTest.cs} (87%) diff --git a/NBi.Core/Calculation/BaseRankingFilter.cs b/NBi.Core/Calculation/BaseRankingFilter.cs index 53d098fbb..20d9cc432 100644 --- a/NBi.Core/Calculation/BaseRankingFilter.cs +++ b/NBi.Core/Calculation/BaseRankingFilter.cs @@ -2,6 +2,8 @@ using NBi.Core.Calculation.Ranking.Scoring; using NBi.Core.Evaluate; using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Filtering; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Data; @@ -13,17 +15,17 @@ namespace NBi.Core.Calculation { public abstract class BaseRankingFilter : IResultSetFilter { - protected readonly IColumnIdentifier operand; - protected readonly ColumnType columnType; - protected readonly IEnumerable aliases; - protected readonly IEnumerable expressions; + protected IColumnIdentifier Operand { get; } + protected ColumnType ColumnType { get; } + protected IEnumerable Aliases { get; } + protected IEnumerable Expressions { get; } protected BaseRankingFilter(IColumnIdentifier operand, ColumnType columnType, IEnumerable aliases, IEnumerable expressions) { - this.operand = operand; - this.columnType = columnType; - this.aliases = aliases; - this.expressions = expressions; + this.Operand = operand; + this.ColumnType = columnType; + this.Aliases = aliases; + this.Expressions = expressions; } public ResultSet.ResultSet AntiApply(ResultSet.ResultSet rs) @@ -32,7 +34,7 @@ public ResultSet.ResultSet AntiApply(ResultSet.ResultSet rs) public ResultSet.ResultSet Apply(ResultSet.ResultSet rs) { IList subset = new List(); - var scorer = new DataRowScorer(operand, aliases, expressions); + var scorer = new DataRowScorer(Operand, Aliases, Expressions); foreach (DataRow row in rs.Rows) { var score = scorer.Execute(row); diff --git a/NBi.Core/Calculation/Combination/AndCombinationPredicateFilter.cs b/NBi.Core/Calculation/Combination/AndCombinationPredicateFilter.cs deleted file mode 100644 index ebafa1fd7..000000000 --- a/NBi.Core/Calculation/Combination/AndCombinationPredicateFilter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation.Predicate.Combination -{ - class AndCombinationPredicateFilter : BaseCombinationPredicateFilter - { - public override string Description { get => "and"; } - - public AndCombinationPredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IEnumerable predications) - : base(serviceLocator, context, aliases, expressions, predications) - { } - - protected override bool RowApply(Context context) - { - var result = true; - var enumerator = predications.GetEnumerator(); - while (enumerator.MoveNext() && result) - { - var value = GetValueFromRow(context, enumerator.Current.Operand); - result = enumerator.Current.Predicate.Execute(value); - } - return result; - } - - } -} diff --git a/NBi.Core/Calculation/Combination/BaseCombinationPredicateFilter.cs b/NBi.Core/Calculation/Combination/BaseCombinationPredicateFilter.cs deleted file mode 100644 index 000da24cb..000000000 --- a/NBi.Core/Calculation/Combination/BaseCombinationPredicateFilter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation.Predicate.Combination -{ - abstract class BaseCombinationPredicateFilter : BasePredicateFilter - { - protected readonly IEnumerable predications; - - public abstract string Description { get; } - - internal BaseCombinationPredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IEnumerable predications) - : base(serviceLocator, context, aliases, expressions) - { - this.predications = predications; - } - - public override string Describe() - { - var sb = new StringBuilder(); - foreach (var predication in predications) - { - sb.Append(predication.Operand); - sb.Append(" "); - sb.Append(predication.Predicate.ToString()); - sb.Append(" "); - sb.Append(this.Description); - sb.Append(" "); - } - sb.Remove(sb.Length - this.Description.Length - 2, this.Description.Length + 2); - sb.Append("."); - return sb.ToString(); - } - } -} diff --git a/NBi.Core/Calculation/Combination/OrCombinationPredicateFilter.cs b/NBi.Core/Calculation/Combination/OrCombinationPredicateFilter.cs deleted file mode 100644 index 6e32a42bf..000000000 --- a/NBi.Core/Calculation/Combination/OrCombinationPredicateFilter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation.Predicate.Combination -{ - class OrCombinationPredicateFilter : BaseCombinationPredicateFilter - { - public override string Description { get => "or"; } - - public OrCombinationPredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IEnumerable predications) - : base(serviceLocator, context, aliases, expressions, predications) - { } - - protected override bool RowApply(Context context) - { - var result = false; - var enumerator = predications.GetEnumerator(); - while (enumerator.MoveNext() && !result) - { - var value = GetValueFromRow(context, enumerator.Current.Operand); - result = enumerator.Current.Predicate.Execute(value); - } - return result; - } - - } -} diff --git a/NBi.Core/Calculation/Combination/XOrCombinationPredicateFilter.cs b/NBi.Core/Calculation/Combination/XOrCombinationPredicateFilter.cs deleted file mode 100644 index a317b8196..000000000 --- a/NBi.Core/Calculation/Combination/XOrCombinationPredicateFilter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NBi.Core.Calculation.Predicate; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation.Predicate.Combination -{ - class XOrCombinationPredicateFilter : BaseCombinationPredicateFilter - { - public override string Description { get => "or"; } - - public XOrCombinationPredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IEnumerable predications) - : base(serviceLocator, context, aliases, expressions, predications) - { } - - protected override bool RowApply(Context context) - { - var result = false; - foreach (var predication in predications) - { - var value = GetValueFromRow(context, predication.Operand); - result ^= predication.Predicate.Execute(value); - } - return result; - } - - } -} diff --git a/NBi.Core/Calculation/FilterGroupByFilter.cs b/NBi.Core/Calculation/FilterGroupByFilter.cs deleted file mode 100644 index 49d487fc5..000000000 --- a/NBi.Core/Calculation/FilterGroupByFilter.cs +++ /dev/null @@ -1,47 +0,0 @@ -using NBi.Core.Calculation.Grouping; -using NBi.Core.ResultSet; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation -{ - class FilterGroupByFilter: IResultSetFilter - { - private readonly IResultSetFilter filter; - private readonly IByColumnGrouping groupBy; - - public FilterGroupByFilter(IResultSetFilter filter, IByColumnGrouping groupBy) - { - this.filter = filter; - this.groupBy = groupBy; - } - - public ResultSet.ResultSet Apply(ResultSet.ResultSet rs) - { - var newRs = rs.Clone(); - var groups = groupBy.Execute(rs); - foreach (var group in groups) - { - var groupRs = new ResultSet.ResultSet(); - groupRs.Load(group.Value); - var filtered = filter.Apply(groupRs); - newRs.AddRange(filtered.Rows.Cast()); - } - return newRs; - } - - public ResultSet.ResultSet AntiApply(ResultSet.ResultSet rs) - { - throw new NotImplementedException(); - } - - public string Describe() - { - throw new NotImplementedException(); - } - } -} diff --git a/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs b/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs new file mode 100644 index 000000000..baaaf92c8 --- /dev/null +++ b/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs @@ -0,0 +1,42 @@ +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; +using NBi.Extensibility; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping.CaseBased +{ + class GroupByCase + { + protected IEnumerable Cases { get; } + + public GroupByCase(IEnumerable cases) + => Cases = cases; + + public IDictionary Execute(ResultSet.ResultSet resultSet, Context context) + { + var stopWatch = new Stopwatch(); + var dico = new Dictionary(); + stopWatch.Start(); + + foreach (DataRow row in resultSet.Rows) + { + context.Switch(row); + var predication = Cases.FirstOrDefault(p => p.Execute(context)); + + if (!dico.ContainsKey(predication)) + dico.Add(predication, row.Table.Clone()); + dico[predication].ImportRow(row); + } + + Trace.WriteLineIf(NBiTraceSwitch.TraceInfo, $"Building rows' groups by cases: {dico.Count} [{stopWatch.Elapsed.ToString(@"d\d\.hh\h\:mm\m\:ss\s\ \+fff\m\s")}"); + return dico; + + } + } +} diff --git a/NBi.Core/Calculation/Grouping/AbstractByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs similarity index 77% rename from NBi.Core/Calculation/Grouping/AbstractByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs index 17c27418c..a1ad0a825 100644 --- a/NBi.Core/Calculation/Grouping/AbstractByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs @@ -8,9 +8,9 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Calculation.Grouping +namespace NBi.Core.Calculation.Grouping.ColumnBased { - public abstract class AbstractByColumnGrouping : IByColumnGrouping + public abstract class AbstractByColumnGrouping : IGroupBy { protected ISettingsResultSet Settings { get; } @@ -22,7 +22,7 @@ public AbstractByColumnGrouping(ISettingsResultSet settings) public IDictionary Execute(ResultSet.ResultSet resultSet) { var stopWatch = new Stopwatch(); - var dico = new Dictionary(); + var dico = new Dictionary(new KeyCollectionEqualityComparer()); var keyComparer = BuildDataRowsKeyComparer(resultSet.Table); stopWatch.Start(); @@ -33,8 +33,7 @@ public IDictionary Execute(ResultSet.ResultSet resultS dico.Add(key, row.Table.Clone()); dico[key].ImportRow(row); } - Trace.WriteLineIf(NBiTraceSwitch.TraceInfo, string.Format("Building rows' groups: {0} [{1}]", dico.Count, stopWatch.Elapsed.ToString(@"d\d\.hh\h\:mm\m\:ss\s\ \+fff\m\s"))); - + Trace.WriteLineIf(NBiTraceSwitch.TraceInfo, $"Building rows' groups: {dico.Count} [{stopWatch.Elapsed.ToString(@"d\d\.hh\h\:mm\m\:ss\s\ \+fff\m\s")})]"); return dico; } diff --git a/NBi.Core/Calculation/Grouping/NameByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs similarity index 91% rename from NBi.Core/Calculation/Grouping/NameByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs index dfbfff06d..d82d0b280 100644 --- a/NBi.Core/Calculation/Grouping/NameByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using NBi.Core.ResultSet; -namespace NBi.Core.Calculation.Grouping +namespace NBi.Core.Calculation.Grouping.ColumnBased { class NameByColumnGrouping : AbstractByColumnGrouping { diff --git a/NBi.Core/Calculation/Grouping/OrdinalByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs similarity index 92% rename from NBi.Core/Calculation/Grouping/OrdinalByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs index d8ecc1a53..f811ac84b 100644 --- a/NBi.Core/Calculation/Grouping/OrdinalByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using NBi.Core.ResultSet; -namespace NBi.Core.Calculation.Grouping +namespace NBi.Core.Calculation.Grouping.ColumnBased { class OrdinalByColumnGrouping : AbstractByColumnGrouping { diff --git a/NBi.Core/Calculation/Grouping/ByColumnGroupingFactory.cs b/NBi.Core/Calculation/Grouping/GroupByFactory.cs similarity index 90% rename from NBi.Core/Calculation/Grouping/ByColumnGroupingFactory.cs rename to NBi.Core/Calculation/Grouping/GroupByFactory.cs index c74922c8f..933d0c4c9 100644 --- a/NBi.Core/Calculation/Grouping/ByColumnGroupingFactory.cs +++ b/NBi.Core/Calculation/Grouping/GroupByFactory.cs @@ -1,4 +1,5 @@ -using NBi.Core.ResultSet; +using NBi.Core.Calculation.Grouping.ColumnBased; +using NBi.Core.ResultSet; using NBi.Core.ResultSet.Equivalence; using NBi.Core.Scalar.Comparer; using NBi.Core.Transformation; @@ -11,11 +12,11 @@ namespace NBi.Core.Calculation.Grouping { - public class ByColumnGroupingFactory + public class GroupByFactory { - public IByColumnGrouping None() => new NoneGrouping(); + public IGroupBy None() => new NoneGrouping(); - public IByColumnGrouping Instantiate(IEnumerable columns) + public IGroupBy Instantiate(IEnumerable columns) { if ((columns?.Count() ?? 0) == 0) return new NoneGrouping(); diff --git a/NBi.Core/Calculation/Grouping/IByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/IGroupBy.cs similarity index 88% rename from NBi.Core/Calculation/Grouping/IByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/IGroupBy.cs index 674486e1d..25363ad11 100644 --- a/NBi.Core/Calculation/Grouping/IByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/IGroupBy.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Calculation.Grouping { - public interface IByColumnGrouping + public interface IGroupBy { IDictionary Execute(ResultSet.ResultSet resultSet); } diff --git a/NBi.Core/Calculation/Grouping/NoneGrouping.cs b/NBi.Core/Calculation/Grouping/NoneGrouping.cs index f56823efc..6734f342f 100644 --- a/NBi.Core/Calculation/Grouping/NoneGrouping.cs +++ b/NBi.Core/Calculation/Grouping/NoneGrouping.cs @@ -8,13 +8,13 @@ namespace NBi.Core.Calculation.Grouping { - sealed class NoneGrouping : IByColumnGrouping + sealed class NoneGrouping : IGroupBy { public IDictionary Execute(ResultSet.ResultSet resultSet) { return new Dictionary() { - { new KeyCollection(new object[]{ }), resultSet.Table } + { new KeyCollection(Array.Empty()), resultSet.Table } }; } } diff --git a/NBi.Core/Calculation/Predication/AndCombinationPredication.cs b/NBi.Core/Calculation/Predication/AndCombinationPredication.cs new file mode 100644 index 000000000..c60207fee --- /dev/null +++ b/NBi.Core/Calculation/Predication/AndCombinationPredication.cs @@ -0,0 +1,28 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + class AndCombinationPredication : BaseCombinationPredication + { + public override string Description { get => "and"; } + + public AndCombinationPredication(IEnumerable predications) + : base(predications) + { } + + protected override bool ContinueCondition(bool state) + => state; + + protected override bool StartState() + => true; + } +} diff --git a/NBi.Core/Calculation/Predication/BaseCombinationPredication.cs b/NBi.Core/Calculation/Predication/BaseCombinationPredication.cs new file mode 100644 index 000000000..a4df1d0cf --- /dev/null +++ b/NBi.Core/Calculation/Predication/BaseCombinationPredication.cs @@ -0,0 +1,51 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + abstract class BaseCombinationPredication : ReadOnlyCollection, IPredication + { + + public abstract string Description { get; } + + internal BaseCombinationPredication(IEnumerable predications) + : base(predications.ToList()) { } + + public string Describe() + { + var sb = new StringBuilder(); + foreach (var predication in this) + { + sb.Append(predication.Describe()); + sb.Append(" "); + sb.Append(this.Description); + sb.Append(" "); + } + sb.Remove(sb.Length - this.Description.Length - 2, this.Description.Length + 2); + sb.Append("."); + return sb.ToString(); + } + + public bool Execute(Context context) + { + var state = StartState(); + var enumerator = this.GetEnumerator(); + while (enumerator.MoveNext() && ContinueCondition(state)) + state = Calculate(state, enumerator.Current.Execute(context)); + return state; + } + + protected abstract bool ContinueCondition(bool state); + protected abstract bool StartState(); + protected virtual bool Calculate(bool previousState, bool currentResult) => currentResult; + } +} diff --git a/NBi.Core/Calculation/Predication/IPredication.cs b/NBi.Core/Calculation/Predication/IPredication.cs new file mode 100644 index 000000000..ce42ca8cf --- /dev/null +++ b/NBi.Core/Calculation/Predication/IPredication.cs @@ -0,0 +1,16 @@ +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + public interface IPredication + { + bool Execute(Context context); + string Describe(); + } +} diff --git a/NBi.Core/Calculation/Predication/OrCombinationPredication.cs b/NBi.Core/Calculation/Predication/OrCombinationPredication.cs new file mode 100644 index 000000000..8b7f6756e --- /dev/null +++ b/NBi.Core/Calculation/Predication/OrCombinationPredication.cs @@ -0,0 +1,30 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + class OrCombinationPredication : BaseCombinationPredication + { + public override string Description { get => "or"; } + + public OrCombinationPredication(IEnumerable predications) + : base(predications) + { } + + + protected override bool ContinueCondition(bool state) + => !state; + + protected override bool StartState() + => false; + + } +} diff --git a/NBi.Core/Calculation/Predication/PredicationFactory.cs b/NBi.Core/Calculation/Predication/PredicationFactory.cs new file mode 100644 index 000000000..6b2a94d76 --- /dev/null +++ b/NBi.Core/Calculation/Predication/PredicationFactory.cs @@ -0,0 +1,32 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.ResultSet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + class PredicationFactory + { + public IPredication Instantiate(IPredicate predicate, IColumnIdentifier operand) + => new SinglePredication(predicate, operand); + + public IPredication Instantiate(IEnumerable predications, CombinationOperator combinationOperator) + { + switch (combinationOperator) + { + case CombinationOperator.Or: + return new OrCombinationPredication(predications); + case CombinationOperator.XOr: + return new XOrCombinationPredication(predications); + case CombinationOperator.And: + return new AndCombinationPredication(predications); + default: + throw new ArgumentOutOfRangeException(nameof(combinationOperator)); + } + } + } +} diff --git a/NBi.Core/Calculation/Predication/SinglePredication.cs b/NBi.Core/Calculation/Predication/SinglePredication.cs new file mode 100644 index 000000000..05039e25e --- /dev/null +++ b/NBi.Core/Calculation/Predication/SinglePredication.cs @@ -0,0 +1,37 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.ResultSet; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + class SinglePredication : IPredication + { + public IPredicate Predicate { get; } + public IColumnIdentifier Operand { get; } + protected internal RowValueExtractor Extractor { get; } = new RowValueExtractor(new ServiceLocator()); + + public SinglePredication(IPredicate predicate, IColumnIdentifier operand) + => (Predicate, Operand) = (predicate, operand); + + public bool Execute(Context context) + => Predicate.Execute(Extractor.Execute(context, Operand)); + + public virtual string Describe() + { + var sb = new StringBuilder(); + sb.Append(Operand.Label); + sb.Append(" "); + sb.Append(Predicate.ToString()); + sb.Append("."); + return sb.ToString(); + } + } +} diff --git a/NBi.Core/Calculation/Predication/XOrCombinationPredication.cs b/NBi.Core/Calculation/Predication/XOrCombinationPredication.cs new file mode 100644 index 000000000..b614efb72 --- /dev/null +++ b/NBi.Core/Calculation/Predication/XOrCombinationPredication.cs @@ -0,0 +1,31 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Predication +{ + class XOrCombinationPredication : BaseCombinationPredication + { + public override string Description { get => "xor"; } + + public XOrCombinationPredication(IEnumerable predications) + : base(predications) + { } + + protected override bool ContinueCondition(bool state) + => true; + + protected override bool StartState() + => false; + + protected override bool Calculate(bool currentState, bool lastResult) + => currentState ^ lastResult; + } +} diff --git a/NBi.Core/Calculation/Ranking/AbstractRanking.cs b/NBi.Core/Calculation/Ranking/AbstractRanking.cs index a2196766e..5ee34b278 100644 --- a/NBi.Core/Calculation/Ranking/AbstractRanking.cs +++ b/NBi.Core/Calculation/Ranking/AbstractRanking.cs @@ -50,7 +50,7 @@ protected override void InsertRow(ScoredObject newObj, ref IList l protected virtual bool RowCompare(ScoredObject oldObj, ScoredObject newObj) { - switch (columnType) + switch (ColumnType) { case ColumnType.Text: return RowCompare(oldObj, newObj); case ColumnType.Numeric: return RowCompare(oldObj, newObj); @@ -65,7 +65,7 @@ protected virtual bool RowCompare(ScoredObject oldObj, ScoredObject newObj) var factory = new PredicateFactory(); var predicateArgs = new ReferencePredicateArgs() { - ColumnType = columnType, + ColumnType = ColumnType, ComparerType = GetComparerType(), Reference = new LiteralScalarResolver(oldObj.Score) }; diff --git a/NBi.Core/Calculation/ResultSetFilterFactory.cs b/NBi.Core/Calculation/ResultSetFilterFactory.cs deleted file mode 100644 index 3a4486bac..000000000 --- a/NBi.Core/Calculation/ResultSetFilterFactory.cs +++ /dev/null @@ -1,78 +0,0 @@ -using NBi.Core.Calculation.Grouping; -using NBi.Core.Calculation.Predicate; -using NBi.Core.Calculation.Predicate.Combination; -using NBi.Core.Calculation.Ranking; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.ResultSet; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation -{ - public class ResultSetFilterFactory - { - private ServiceLocator ServiceLocator { get; } - private Context Context { get; } - - public ResultSetFilterFactory(ServiceLocator serviceLocator, Context context) - => (ServiceLocator, Context) = (serviceLocator, context); - - public IResultSetFilter Instantiate(IEnumerable aliases, IEnumerable expressions, PredicationArgs predicationArgs) - { - if (predicationArgs.Identifier == null) - throw new ArgumentException("You must specify an operand for a predication. The operand is the column or alias or expression on which the predicate will be evaluated."); - - var factory = new PredicateFactory(); - var predicate = factory.Instantiate(predicationArgs.Predicate); - - var pf = new SinglePredicateFilter(ServiceLocator, Context, aliases, expressions, predicationArgs.Identifier, predicate.Execute, predicate.ToString); - - return pf; - } - - public IResultSetFilter Instantiate(IEnumerable aliases, IEnumerable expressions, CombinationOperator combinationOperator, IEnumerable predicationArgs) - { - var predications = new List(); - - var factory = new PredicateFactory(); - foreach (var predicationArg in predicationArgs) - { - if (predicationArg.Identifier == null) - throw new ArgumentException("You must specify an operand for a predicate. The operand is the column or alias or expression on which the predicate will be evaluated."); - - var predicate = factory.Instantiate(predicationArg.Predicate); - predications.Add(new Predication(predicate, predicationArg.Identifier)); - } - - switch (combinationOperator) - { - case CombinationOperator.Or: - return new OrCombinationPredicateFilter(ServiceLocator, Context, aliases, expressions, predications); - case CombinationOperator.XOr: - return new XOrCombinationPredicateFilter(ServiceLocator, Context, aliases, expressions, predications); - case CombinationOperator.And: - return new AndCombinationPredicateFilter(ServiceLocator, Context, aliases, expressions, predications); - default: - throw new ArgumentOutOfRangeException(nameof(combinationOperator)); - } - } - - - public IResultSetFilter Instantiate(IRankingInfo rankingInfo, IEnumerable columns) - { - var groupingFactory = new ByColumnGroupingFactory(); - var grouping = groupingFactory.Instantiate(columns); - - var rankingFactory = new RankingFactory(); - var ranking = rankingFactory.Instantiate(rankingInfo); - - return new FilterGroupByFilter(ranking, grouping); - } - } -} diff --git a/NBi.Core/Calculation/BasePredicateFilter.cs b/NBi.Core/Calculation/RowValueExtractor.cs similarity index 60% rename from NBi.Core/Calculation/BasePredicateFilter.cs rename to NBi.Core/Calculation/RowValueExtractor.cs index 9a332f5f4..a116d75a3 100644 --- a/NBi.Core/Calculation/BasePredicateFilter.cs +++ b/NBi.Core/Calculation/RowValueExtractor.cs @@ -14,59 +14,14 @@ namespace NBi.Core.Calculation { - public abstract class BasePredicateFilter : IResultSetFilter + public class RowValueExtractor { private ServiceLocator ServiceLocator { get; } - private Context Context { get; } - protected readonly IEnumerable expressions; - protected readonly IEnumerable aliases; - protected BasePredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions) - => (ServiceLocator, Context, this.aliases, this.expressions) = (serviceLocator, context, aliases, expressions); + public RowValueExtractor(ServiceLocator serviceLocator) + => (ServiceLocator) = (serviceLocator); - public ResultSet.ResultSet AntiApply(ResultSet.ResultSet rs) - { - return Apply(rs, (x => !x)); - } - - public ResultSet.ResultSet Apply(ResultSet.ResultSet rs) - { - return Apply(rs, (x => x)); - } - - protected ResultSet.ResultSet Apply(ResultSet.ResultSet rs, Func onApply) - { - var filteredRs = new ResultSet.ResultSet(); - var table = rs.Table.Clone(); - filteredRs.Load(table); - filteredRs.Table.Clear(); - - foreach (DataRow row in rs.Rows) - { - Context.Switch(row); - if (onApply(RowApply(Context))) - { - if (filteredRs.Rows.Count == 0 && filteredRs.Columns.Count != row.Table.Columns.Count) - { - foreach (DataColumn column in row.Table.Columns) - { - if (!filteredRs.Columns.Cast().Any(x => x.ColumnName == column.ColumnName)) - filteredRs.Columns.Add(column.ColumnName, typeof(object)); - } - } - filteredRs.Table.ImportRow(row); - } - } - - filteredRs.Table.AcceptChanges(); - return filteredRs; - } - - protected abstract bool RowApply(Context context); - public bool Execute(Context context) => RowApply(context); - - - protected object GetValueFromRow(Context context, IColumnIdentifier identifier) + public object Execute(Context context, IColumnIdentifier identifier) { if (identifier is ColumnOrdinalIdentifier) { @@ -78,11 +33,11 @@ protected object GetValueFromRow(Context context, IColumnIdentifier identifier) } var name = (identifier as ColumnNameIdentifier).Name; - var alias = aliases.SingleOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); + var alias = context.Aliases?.SingleOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); if (alias != null) return context.CurrentRow.ItemArray[alias.Column]; - var expression = expressions.SingleOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); + var expression = context.Expressions?.SingleOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); if (expression != null) { var result = EvaluateExpression(expression, context); @@ -102,8 +57,8 @@ protected object GetValueFromRow(Context context, IColumnIdentifier identifier) return context.CurrentRow[column.ColumnName]; var existingNames = context.CurrentRow.Table.Columns.Cast().Select(x => x.ColumnName) - .Union(aliases.Select(x => x.Name) - .Union(expressions.Select(x => x.Name))); + .Union(context.Aliases.Select(x => x.Name) + .Union(context.Expressions.Select(x => x.Name))); throw new ArgumentException($"The value '{name}' is not recognized as a column position, a column name, a column alias or an expression. Possible arguments are: '{string.Join("', '", existingNames.ToArray())}'"); } @@ -117,7 +72,7 @@ protected object EvaluateExpression(IColumnExpression expression, Context contex exp.EvaluateParameter += delegate (string name, NCalc.ParameterArgs args) { - args.Result = GetValueFromRow(context, factory.Instantiate(name)); + args.Result = Execute(context, factory.Instantiate(name)); }; return exp.Evaluate(); @@ -126,7 +81,7 @@ protected object EvaluateExpression(IColumnExpression expression, Context contex { var parse = expression.Value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); var variable = new ColumnIdentifierFactory().Instantiate(parse.ElementAt(0)); - var value = GetValueFromRow(context, variable); + var value = Execute(context, variable); foreach (var nativeFunction in parse.Skip(1)) { @@ -141,8 +96,6 @@ protected object EvaluateExpression(IColumnExpression expression, Context contex throw new ArgumentOutOfRangeException($"The language {expression.Language} is not supported during the evaluation of an expression."); } - public abstract string Describe(); - private class TransformationInfo : ITransformationInfo { public ColumnType OriginalType { get; set; } diff --git a/NBi.Core/Calculation/SinglePredicateFilter.cs b/NBi.Core/Calculation/SinglePredicateFilter.cs index 3daa1cc65..599bbbd86 100644 --- a/NBi.Core/Calculation/SinglePredicateFilter.cs +++ b/NBi.Core/Calculation/SinglePredicateFilter.cs @@ -1,42 +1,40 @@ -using NBi.Core.Calculation.Predicate; -using NBi.Core.Evaluate; -using NBi.Core.Injection; -using NBi.Core.ResultSet; -using NBi.Core.Variable; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +//using NBi.Core.Calculation.Predicate; +//using NBi.Core.Evaluate; +//using NBi.Core.Injection; +//using NBi.Core.ResultSet; +//using NBi.Core.Variable; +//using System; +//using System.Collections.Generic; +//using System.Data; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; -namespace NBi.Core.Calculation -{ - class SinglePredicateFilter : BasePredicateFilter - { - private readonly Func implementation; - private readonly IColumnIdentifier operand; - private readonly Func describeFunction; +//namespace NBi.Core.Calculation +//{ +// class SinglePredicateFilter : RowValueExtractor +// { +// private readonly Func implementation; +// private readonly IColumnIdentifier operand; +// private readonly Func describeFunction; - public SinglePredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IColumnIdentifier operand, Func implementation, Func describeFunction) - : base(serviceLocator, context, aliases, expressions) - { - this.operand = operand; - this.implementation = implementation; - this.describeFunction = describeFunction; - } +// public SinglePredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IColumnIdentifier operand, Func implementation, Func describeFunction) +// : base(serviceLocator, context, aliases, expressions) +// { +// this.operand = operand; +// this.implementation = implementation; +// this.describeFunction = describeFunction; +// } - protected override bool RowApply(Context context) - { - var value = GetValueFromRow(context, operand); - return implementation(value); - } +// protected override bool RowApply(Context context) +// { +// var value = GetValueFromRow(context, operand); +// return implementation(value); +// } - - - public override string Describe() - { - return $"{operand.Label} {describeFunction()}."; - } - } -} +// public override string Describe() +// { +// return $"{operand.Label} {describeFunction()}."; +// } +// } +//} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index c63d2b1fe..ca659aa92 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -145,20 +145,24 @@ - - + + + + + - - + + + - - - - - - + + + + + + - + @@ -210,7 +214,7 @@ - + @@ -221,9 +225,9 @@ - - - + + + @@ -504,6 +508,9 @@ + + + diff --git a/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs b/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs index 3ba87f6af..64ae7e27c 100644 --- a/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs @@ -47,7 +47,7 @@ public ResultSet Execute(ResultSet rs) dataTable.Columns.Add(new DataColumn(namingStrategy.Execute(headerValue, valueColumn.ColumnName), typeof(object))); - var groupbyFactory = new ByColumnGroupingFactory(); + var groupbyFactory = new GroupByFactory(); var groupbyEngine = groupbyFactory.Instantiate(Args.GroupBys); var groups = groupbyEngine.Execute(rs); foreach (var group in groups) diff --git a/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs b/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs index 4b68734c5..90af3014e 100644 --- a/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs @@ -41,7 +41,7 @@ public ResultSet Execute(ResultSet rs) aggregations.Add(factory.Instantiate(aggregation)); } - var groupbyFactory = new ByColumnGroupingFactory(); + var groupbyFactory = new GroupByFactory(); var groupbyEngine = groupbyFactory.Instantiate(Args.GroupBys); var groups = groupbyEngine.Execute(rs); foreach (var group in groups) diff --git a/NBi.Core/ResultSet/Filtering/BaseFilter.cs b/NBi.Core/ResultSet/Filtering/BaseFilter.cs new file mode 100644 index 000000000..1a358a148 --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/BaseFilter.cs @@ -0,0 +1,56 @@ +using NBi.Core.Calculation.Predicate; +using NBi.Core.Evaluate; +using NBi.Core.ResultSet; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + public abstract class BaseFilter : IResultSetFilter + { + protected Context Context { get; } + protected BaseFilter(Context context) + => Context = context; + + public ResultSet AntiApply(ResultSet rs) => Apply(rs, (x => !x)); + + public ResultSet Apply(ResultSet rs) => Apply(rs, (x => x)); + + protected ResultSet Apply(ResultSet rs, Func onApply) + { + var filteredRs = new ResultSet(); + var table = rs.Table.Clone(); + filteredRs.Load(table); + filteredRs.Table.Clear(); + + foreach (DataRow row in rs.Rows) + { + Context.Switch(row); + if (onApply(RowApply(Context))) + { + if (filteredRs.Rows.Count == 0 && filteredRs.Columns.Count != row.Table.Columns.Count) + { + foreach (DataColumn column in row.Table.Columns) + { + if (!filteredRs.Columns.Cast().Any(x => x.ColumnName == column.ColumnName)) + filteredRs.Columns.Add(column.ColumnName, typeof(object)); + } + } + filteredRs.Table.ImportRow(row); + } + } + + filteredRs.Table.AcceptChanges(); + return filteredRs; + } + + protected abstract bool RowApply(Context context); + + public abstract string Describe(); + } +} \ No newline at end of file diff --git a/NBi.Core/ResultSet/Filtering/GroupByFilter.cs b/NBi.Core/ResultSet/Filtering/GroupByFilter.cs new file mode 100644 index 000000000..aa8135cc6 --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/GroupByFilter.cs @@ -0,0 +1,41 @@ +using NBi.Core.Calculation.Grouping; +using NBi.Core.ResultSet; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + class GroupByFilter: IResultSetFilter + { + private IResultSetFilter Filter { get; } + private IGroupBy GroupBy { get; } + + public GroupByFilter(IResultSetFilter filter, IGroupBy groupBy) + => (Filter, GroupBy) = (filter, groupBy); + + public ResultSet Apply(ResultSet rs) + { + var newRs = rs.Clone(); + var groups = GroupBy.Execute(rs); + foreach (var group in groups) + { + var groupRs = new ResultSet(); + groupRs.Load(group.Value); + var filtered = Filter.Apply(groupRs); + newRs.AddRange(filtered.Rows.Cast()); + } + return newRs; + } + + public ResultSet AntiApply(ResultSet rs) + => throw new NotImplementedException(); + + public string Describe() + => throw new NotImplementedException(); + } +} diff --git a/NBi.Core/Calculation/IResultSetFilter.cs b/NBi.Core/ResultSet/Filtering/IResultSetFilter.cs similarity index 51% rename from NBi.Core/Calculation/IResultSetFilter.cs rename to NBi.Core/ResultSet/Filtering/IResultSetFilter.cs index 1b6e86f5a..835966744 100644 --- a/NBi.Core/Calculation/IResultSetFilter.cs +++ b/NBi.Core/ResultSet/Filtering/IResultSetFilter.cs @@ -1,16 +1,16 @@ -using System; +using NBi.Core.Variable; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using RS = NBi.Core.ResultSet; -namespace NBi.Core.Calculation +namespace NBi.Core.ResultSet.Filtering { public interface IResultSetFilter { - RS.ResultSet Apply(RS.ResultSet rs); - RS.ResultSet AntiApply(RS.ResultSet rs); + ResultSet Apply(ResultSet rs); + ResultSet AntiApply(ResultSet rs); string Describe(); } diff --git a/NBi.Core/Calculation/NoneFilter.cs b/NBi.Core/ResultSet/Filtering/NoneFilter.cs similarity index 60% rename from NBi.Core/Calculation/NoneFilter.cs rename to NBi.Core/ResultSet/Filtering/NoneFilter.cs index 39dc53e43..7395183d6 100644 --- a/NBi.Core/Calculation/NoneFilter.cs +++ b/NBi.Core/ResultSet/Filtering/NoneFilter.cs @@ -1,34 +1,32 @@ -using System; +using NBi.Core.Variable; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Calculation +namespace NBi.Core.ResultSet.Filtering { class NoneFilter : IResultSetFilter { - public ResultSet.ResultSet Apply(ResultSet.ResultSet rs) + public ResultSet Apply(ResultSet rs) { if (rs == null) throw new ArgumentNullException(); return rs; } - public ResultSet.ResultSet AntiApply(ResultSet.ResultSet rs) + public ResultSet AntiApply(ResultSet rs) { if (rs == null) throw new ArgumentNullException(); - var filteredRs = new ResultSet.ResultSet(); + var filteredRs = new ResultSet(); var table = rs.Table.Clone(); filteredRs.Load(table); return filteredRs; } - public string Describe() - { - return "none"; - } + public string Describe() => "none"; } } diff --git a/NBi.Core/ResultSet/Filtering/PredicationFilter.cs b/NBi.Core/ResultSet/Filtering/PredicationFilter.cs new file mode 100644 index 000000000..e504de1a8 --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/PredicationFilter.cs @@ -0,0 +1,25 @@ +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + class PredicationFilter : BaseFilter + { + private IPredication Predication { get; } + + public PredicationFilter(IPredication predication, Context context) + : base(context) => Predication = predication; + + protected override bool RowApply(Context context) + => Predication.Execute(context); + + public override string Describe() + => $"{Predication.Describe()}"; + } +} diff --git a/NBi.Core/Calculation/ResultSetFilter.cs b/NBi.Core/ResultSet/Filtering/ResultSetFilter.cs similarity index 86% rename from NBi.Core/Calculation/ResultSetFilter.cs rename to NBi.Core/ResultSet/Filtering/ResultSetFilter.cs index 9f8b00a64..63a6e8818 100644 --- a/NBi.Core/Calculation/ResultSetFilter.cs +++ b/NBi.Core/ResultSet/Filtering/ResultSetFilter.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Calculation +namespace NBi.Core.ResultSet.Filtering { public abstract class ResultSetFilter { diff --git a/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs new file mode 100644 index 000000000..850b891ef --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs @@ -0,0 +1,76 @@ +using NBi.Core.Calculation; +using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Calculation.Predicate.Combination; +using NBi.Core.Calculation.Predication; +using NBi.Core.Calculation.Ranking; +using NBi.Core.Evaluate; +using NBi.Core.Injection; +using NBi.Core.ResultSet; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + public class ResultSetFilterFactory + { + private ServiceLocator ServiceLocator { get; } + + public ResultSetFilterFactory(ServiceLocator serviceLocator) + => (ServiceLocator) = (serviceLocator); + + public IResultSetFilter Instantiate(PredicationArgs predicationArgs, Context context) + { + if (predicationArgs.Identifier == null) + throw new ArgumentException("You must specify an operand for a predication. The operand is the column or alias or expression on which the predicate will be evaluated."); + + var factory = new PredicateFactory(); + var predicate = factory.Instantiate(predicationArgs.Predicate); + + var predicationFactory = new PredicationFactory(); + var predication = predicationFactory.Instantiate(predicate, predicationArgs.Identifier); + + var filter = new PredicationFilter(predication, context); + return filter; + } + + public IResultSetFilter Instantiate(CombinationOperator combinationOperator, IEnumerable predicationArgs, Context context) + { + var predications = new List(); + + var predicateFactory = new PredicateFactory(); + var predicationFactory = new PredicationFactory(); + + foreach (var predicationArg in predicationArgs) + { + if (predicationArg.Identifier == null) + throw new ArgumentException("You must specify an operand for a predicate. The operand is the column or alias or expression on which the predicate will be evaluated."); + + var predicate = predicateFactory.Instantiate(predicationArg.Predicate); + var localPredication = predicationFactory.Instantiate(predicate, predicationArg.Identifier); + predications.Add(localPredication); + } + + var predication = predicationFactory.Instantiate(predications, combinationOperator); + var filter = new PredicationFilter(predication, context); + return filter; + } + + + public IResultSetFilter Instantiate(IRankingInfo rankingInfo, IEnumerable columns) + { + var groupingFactory = new GroupByFactory(); + var grouping = groupingFactory.Instantiate(columns); + + var rankingFactory = new RankingFactory(); + var ranking = rankingFactory.Instantiate(rankingInfo); + + return new GroupByFilter(ranking, grouping); + } + } +} diff --git a/NBi.Core/ResultSet/KeyCollectionEqualityComparer.cs b/NBi.Core/ResultSet/KeyCollectionEqualityComparer.cs new file mode 100644 index 000000000..cd3590d7d --- /dev/null +++ b/NBi.Core/ResultSet/KeyCollectionEqualityComparer.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet +{ + class KeyCollectionEqualityComparer : IEqualityComparer + { + public int GetHashCode(object x) + => (x as KeyCollection)?.GetHashCode() ?? 0; + public new bool Equals(object x, object y) + => (x as KeyCollection)?.Equals(y as KeyCollection) ?? false; + } +} diff --git a/NBi.Core/Variable/Context.cs b/NBi.Core/Variable/Context.cs index 64a644d4f..41b0e2d91 100644 --- a/NBi.Core/Variable/Context.cs +++ b/NBi.Core/Variable/Context.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Evaluate; +using System; using System.Collections.Generic; using System.Data; using System.Linq; @@ -9,15 +10,24 @@ namespace NBi.Core.Variable { public class Context { - public IDictionary Variables { get; } + + public IEnumerable Aliases { get; } = new List(); + public IEnumerable Expressions { get; } = new List(); + + public IDictionary Variables { get; } = new Dictionary(); public DataRow CurrentRow { get; private set; } + public static Context None { get; } = new Context(); + + private Context() { } + public Context(IDictionary variables) => Variables = variables; + public Context(IDictionary variables, IEnumerable aliases, IEnumerable expressions) + : this(variables) => (Aliases, Expressions) = (aliases, expressions); + public void Switch(DataRow currentRow) => CurrentRow = currentRow; - - } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs index 38bc3b8fa..4b75b1250 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs @@ -34,6 +34,7 @@ using NBi.Core.ResultSet.Lookup; using NBi.Core.ResultSet.Alteration.Lookup.Strategies.Missing; using NBi.Core.ResultSet.Alteration.Renaming.Strategies.Missing; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Builder.Helper { @@ -84,7 +85,7 @@ public IEnumerable InstantiateAlterations(ResultSetSystemXml resultSetXml private Alter InstantiateFilter(FilterXml filterXml) { var context = new Context(Variables); - var factory = new ResultSetFilterFactory(ServiceLocator, context); + var factory = new ResultSetFilterFactory(ServiceLocator); if (filterXml.Ranking == null) { @@ -99,9 +100,8 @@ private Alter InstantiateFilter(FilterXml filterXml) return factory.Instantiate ( - filterXml.Aliases - , expressions - , new PredicationArgs(filterXml.Predication.Operand, args) + new PredicationArgs(filterXml.Predication.Operand, args) + , context ).Apply; } if (filterXml.Combination != null) @@ -116,10 +116,9 @@ private Alter InstantiateFilter(FilterXml filterXml) return factory.Instantiate ( - filterXml.Aliases - , expressions - , filterXml.Combination.Operator + filterXml.Combination.Operator , predicationArgs + , context ).Apply; } throw new ArgumentException(); diff --git a/NBi.NUnit/Builder/ResultSetNoRowsBuilder.cs b/NBi.NUnit/Builder/ResultSetNoRowsBuilder.cs index 13bdee84d..aec1c374f 100644 --- a/NBi.NUnit/Builder/ResultSetNoRowsBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetNoRowsBuilder.cs @@ -11,6 +11,7 @@ using NBi.Core.Calculation.Predicate; using NBi.Core.ResultSet; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Builder { @@ -40,12 +41,8 @@ protected virtual NBiConstraint InstantiateConstraint() protected IResultSetFilter InstantiateFilter() { - var expressions = new List(); - if (ConstraintXml.Expressions != null) - expressions.AddRange(ConstraintXml.Expressions); - - var context = new Context(Variables); - var factory = new ResultSetFilterFactory(ServiceLocator, context); + var context = new Context(Variables, ConstraintXml.Aliases, ConstraintXml.Expressions); + var factory = new ResultSetFilterFactory(ServiceLocator); if (ConstraintXml.Predication != null) { var helper = new PredicateArgsBuilder(ServiceLocator, context); @@ -53,9 +50,8 @@ protected IResultSetFilter InstantiateFilter() return factory.Instantiate ( - ConstraintXml.Aliases - , expressions - , new PredicationArgs(ConstraintXml.Predication.Operand, args) + new PredicationArgs(ConstraintXml.Predication.Operand, args) + , context ); } else if (ConstraintXml.Combination != null) @@ -71,10 +67,9 @@ protected IResultSetFilter InstantiateFilter() return factory.Instantiate ( - ConstraintXml.Aliases - , expressions - , ConstraintXml.Combination.Operator + ConstraintXml.Combination.Operator , predicationArgs + , context ); } else diff --git a/NBi.NUnit/Builder/ResultSetRowCountBuilder.cs b/NBi.NUnit/Builder/ResultSetRowCountBuilder.cs index 72efd9551..8594e9365 100644 --- a/NBi.NUnit/Builder/ResultSetRowCountBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetRowCountBuilder.cs @@ -14,6 +14,7 @@ using NBi.Core.Scalar; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Builder { @@ -55,8 +56,8 @@ protected NBiConstraint InstantiateConstraint() var value = EvaluatePotentialVariable(comparer.Reference.ToString().Replace(" ", "")); - var context = new Context(Variables); - var factory = new ResultSetFilterFactory(ServiceLocator, context); + var context = new Context(Variables, filterXml.Aliases, expressions); + var factory = new ResultSetFilterFactory(ServiceLocator); if (filterXml.Predication != null) { var helper = new PredicateArgsBuilder(ServiceLocator, context); @@ -64,9 +65,8 @@ protected NBiConstraint InstantiateConstraint() filter = factory.Instantiate ( - filterXml.Aliases - , expressions - , new PredicationArgs(filterXml.Predication.Operand, args) + new PredicationArgs(filterXml.Predication.Operand, args) + , context ); } @@ -82,10 +82,9 @@ protected NBiConstraint InstantiateConstraint() filter = factory.Instantiate ( - filterXml.Aliases - , expressions - , filterXml.Combination.Operator + filterXml.Combination.Operator , predicationArgs + , context ); } if ((value is string & (value as string).EndsWith("%"))) diff --git a/NBi.NUnit/Query/AllRowsConstraint.cs b/NBi.NUnit/Query/AllRowsConstraint.cs index b8d44a7ba..17dcd86cd 100644 --- a/NBi.NUnit/Query/AllRowsConstraint.cs +++ b/NBi.NUnit/Query/AllRowsConstraint.cs @@ -8,6 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework; using NBi.Core.Configuration.FailureReport; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Query { diff --git a/NBi.NUnit/Query/NoRowsConstraint.cs b/NBi.NUnit/Query/NoRowsConstraint.cs index 4f78095ec..cd4e7a49c 100644 --- a/NBi.NUnit/Query/NoRowsConstraint.cs +++ b/NBi.NUnit/Query/NoRowsConstraint.cs @@ -8,6 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework; using NBi.Core.Configuration.FailureReport; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Query { diff --git a/NBi.NUnit/Query/RowCountFilterConstraint.cs b/NBi.NUnit/Query/RowCountFilterConstraint.cs index 031e34a96..12f1e7292 100644 --- a/NBi.NUnit/Query/RowCountFilterConstraint.cs +++ b/NBi.NUnit/Query/RowCountFilterConstraint.cs @@ -9,6 +9,8 @@ using NBi.Framework.FailureMessage.Markdown; using NBi.Framework; using NBi.Core.Configuration.FailureReport; +using NBi.Core.ResultSet.Filtering; +using NBi.Core.Variable; namespace NBi.NUnit.Query { @@ -38,7 +40,7 @@ protected override IDataRowsMessageFormatter BuildFailure() protected override bool doMatch(ResultSet actual) { - actualResultSet = (ResultSet)actual; + actualResultSet = actual; filterResultSet = filterFunction(actualResultSet); return Matches(filterResultSet.Rows.Count); } diff --git a/NBi.NUnit/Query/RowCountFilterPercentageConstraint.cs b/NBi.NUnit/Query/RowCountFilterPercentageConstraint.cs index 95d83d7d7..8a1443aa9 100644 --- a/NBi.NUnit/Query/RowCountFilterPercentageConstraint.cs +++ b/NBi.NUnit/Query/RowCountFilterPercentageConstraint.cs @@ -5,6 +5,7 @@ using NBi.Core.ResultSet; using System.Data; using NBi.Core.Calculation; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Query { diff --git a/NBi.NUnit/Query/SingleRowConstraint.cs b/NBi.NUnit/Query/SingleRowConstraint.cs index 5d86d6b5c..066befb57 100644 --- a/NBi.NUnit/Query/SingleRowConstraint.cs +++ b/NBi.NUnit/Query/SingleRowConstraint.cs @@ -8,6 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework; using NBi.Core.Configuration.FailureReport; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Query { diff --git a/NBi.NUnit/Query/SomeRowsConstraint.cs b/NBi.NUnit/Query/SomeRowsConstraint.cs index c04ee073b..101c10a57 100644 --- a/NBi.NUnit/Query/SomeRowsConstraint.cs +++ b/NBi.NUnit/Query/SomeRowsConstraint.cs @@ -8,6 +8,7 @@ using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework; using NBi.Core.Configuration.FailureReport; +using NBi.Core.ResultSet.Filtering; namespace NBi.NUnit.Query { diff --git a/NBi.Testing.Core/Calculation/Grouping/NameByColumnGroupingTest.cs b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs similarity index 97% rename from NBi.Testing.Core/Calculation/Grouping/NameByColumnGroupingTest.cs rename to NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs index 377ec4caf..c48eb9016 100644 --- a/NBi.Testing.Core/Calculation/Grouping/NameByColumnGroupingTest.cs +++ b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs @@ -1,4 +1,5 @@ using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Comparer; @@ -10,7 +11,7 @@ using System.Threading.Tasks; using static NBi.Core.ResultSet.SettingsOrdinalResultSet; -namespace NBi.Testing.Core.Calculation.Grouping +namespace NBi.Testing.Core.Calculation.Grouping.ColumnBased { public class NameByColumnGroupingTest { diff --git a/NBi.Testing.Core/Calculation/Grouping/OrdinalByColumnGroupingTest.cs b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs similarity index 97% rename from NBi.Testing.Core/Calculation/Grouping/OrdinalByColumnGroupingTest.cs rename to NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs index 9b6e554bb..3e18010df 100644 --- a/NBi.Testing.Core/Calculation/Grouping/OrdinalByColumnGroupingTest.cs +++ b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs @@ -1,4 +1,5 @@ using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Comparer; @@ -10,7 +11,7 @@ using System.Threading.Tasks; using static NBi.Core.ResultSet.SettingsOrdinalResultSet; -namespace NBi.Testing.Core.Calculation.Grouping +namespace NBi.Testing.Core.Calculation.Grouping.ColumnBased { public class OrdinalByColumnGroupingTest { diff --git a/NBi.Testing.Core/Calculation/CultureSensitivePredicateMatchesTest.cs b/NBi.Testing.Core/Calculation/Predicate/CultureSensitivePredicateMatchesTest.cs similarity index 98% rename from NBi.Testing.Core/Calculation/CultureSensitivePredicateMatchesTest.cs rename to NBi.Testing.Core/Calculation/Predicate/CultureSensitivePredicateMatchesTest.cs index b1ab94e3e..4c3d91b12 100644 --- a/NBi.Testing.Core/Calculation/CultureSensitivePredicateMatchesTest.cs +++ b/NBi.Testing.Core/Calculation/Predicate/CultureSensitivePredicateMatchesTest.cs @@ -9,7 +9,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Testing.Core.Calculation +namespace NBi.Testing.Core.Calculation.Predicate { public class CultureSensitivePredicateMatchesTest { diff --git a/NBi.Testing.Core/Calculation/Predication/AndCombinationPredicationTest.cs b/NBi.Testing.Core/Calculation/Predication/AndCombinationPredicationTest.cs new file mode 100644 index 000000000..3cc1b1567 --- /dev/null +++ b/NBi.Testing.Core/Calculation/Predication/AndCombinationPredicationTest.cs @@ -0,0 +1,94 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core; +using NBi.Core.Calculation; +using Moq; +using NBi.Core.Evaluate; +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Resolver; +using System.Data; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; + +namespace NBi.Testing.Unit.Core.Calculation.Predication +{ + public class AndCombinationPredicationTest + { + [Test] + public void Execute_TwoTrue_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.And); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.True); + } + + [Test] + public void Execute_TrueFalse_False() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.And); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.False); + } + + [Test] + public void Execute_FalseTrue_False() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.And); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.False); + } + + [Test] + public void Execute_FalseTrue_StopOnFirst() + { + var leftPredicationMock = new Mock(); + leftPredicationMock.Setup(x => x.Execute(It.IsAny())).Returns(false); + var rightPredicationMock = new Mock(); + rightPredicationMock.Setup(x => x.Execute(It.IsAny())).Returns(true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredicationMock.Object, rightPredicationMock.Object }, CombinationOperator.And); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + predication.Execute(context); + + leftPredicationMock.Verify(x => x.Execute(context), Times.Once); + rightPredicationMock.Verify(x => x.Execute(It.IsAny()), Times.Never); + } + } +} \ No newline at end of file diff --git a/NBi.Testing.Core/Calculation/Predication/OrCombinationPredicationTest.cs b/NBi.Testing.Core/Calculation/Predication/OrCombinationPredicationTest.cs new file mode 100644 index 000000000..e891af53c --- /dev/null +++ b/NBi.Testing.Core/Calculation/Predication/OrCombinationPredicationTest.cs @@ -0,0 +1,112 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core; +using NBi.Core.Calculation; +using Moq; +using NBi.Core.Evaluate; +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Resolver; +using System.Data; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; + +namespace NBi.Testing.Unit.Core.Calculation.Predication +{ + public class OrCombinationPredicationTest + { + [Test] + public void Execute_TwoTrue_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.Or); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.True); + } + + [Test] + public void Execute_TrueFalse_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.Or); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.True); + } + + [Test] + public void Execute_FalseTrue_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.Or); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.True); + } + + + [Test] + public void Execute_FalseFalse_False() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.Or); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + + Assert.That(predication.Execute(context), Is.False); + } + + [Test] + public void Execute_TrueFalse_StopOnFirst() + { + var leftPredicationMock = new Mock(); + leftPredicationMock.Setup(x => x.Execute(It.IsAny())).Returns(true); + var rightPredicationMock = new Mock(); + rightPredicationMock.Setup(x => x.Execute(It.IsAny())).Returns(false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredicationMock.Object, rightPredicationMock.Object }, CombinationOperator.Or); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + context.Switch(row); + predication.Execute(context); + + leftPredicationMock.Verify(x => x.Execute(context), Times.Once); + rightPredicationMock.Verify(x => x.Execute(It.IsAny()), Times.Never); + } + } +} \ No newline at end of file diff --git a/NBi.Testing.Core/Calculation/Predication/XOrCombinationPredicationTest.cs b/NBi.Testing.Core/Calculation/Predication/XOrCombinationPredicationTest.cs new file mode 100644 index 000000000..f889cbcde --- /dev/null +++ b/NBi.Testing.Core/Calculation/Predication/XOrCombinationPredicationTest.cs @@ -0,0 +1,109 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core; +using NBi.Core.Calculation; +using Moq; +using NBi.Core.Evaluate; +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Resolver; +using System.Data; +using NBi.Core.Calculation.Predicate; +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; + +namespace NBi.Testing.Unit.Core.Calculation.Predication +{ + public class XOrCombinationPredicationTest + { + [Test] + public void Execute_TwoTrue_False() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.XOr); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + + Assert.That(predication.Execute(context), Is.False); + } + + [Test] + public void Execute_TwoFalse_False() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.XOr); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + + Assert.That(predication.Execute(context), Is.False); + } + + [Test] + public void Execute_TrueFalse_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.XOr); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + + Assert.That(predication.Execute(context), Is.True); + } + + [Test] + public void Execute_FalseTrue_True() + { + var leftPredication = Mock.Of(x => x.Execute(It.IsAny()) == false); + var RightPredication = Mock.Of(x => x.Execute(It.IsAny()) == true); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { leftPredication, RightPredication }, CombinationOperator.XOr); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + + Assert.That(predication.Execute(context), Is.True); + } + + [Test] + public void Execute_TrueFalseTrue_GoUntilTheEnd() + { + var predicationMock1 = new Mock(); + predicationMock1.Setup(x => x.Execute(It.IsAny())).Returns(true); + var predicationMock2 = new Mock(); + predicationMock2.Setup(x => x.Execute(It.IsAny())).Returns(false); + var predicationMock3 = new Mock(); + predicationMock3.Setup(x => x.Execute(It.IsAny())).Returns(false); + + var factory = new PredicationFactory(); + var predication = factory.Instantiate(new[] { predicationMock1.Object, predicationMock2.Object, predicationMock3.Object }, CombinationOperator.XOr); + + var context = Context.None; + var dt = new DataTable(); + var row = dt.NewRow(); + predication.Execute(context); + + predicationMock1.Verify(x => x.Execute(context), Times.Once); + predicationMock2.Verify(x => x.Execute(context), Times.Once); + predicationMock3.Verify(x => x.Execute(context), Times.Once); + } + } +} \ No newline at end of file diff --git a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs index cdc0fe64f..b3fef70ab 100644 --- a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs @@ -5,6 +5,7 @@ using NBi.Core.Evaluate; using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; diff --git a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs index eb7b4c3a6..7fbb6ba00 100644 --- a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs @@ -5,6 +5,7 @@ using NBi.Core.Evaluate; using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; diff --git a/NBi.Testing.Core/Calculation/SinglePredicateFilterTest.cs b/NBi.Testing.Core/Calculation/SinglePredicateFilterTest.cs deleted file mode 100644 index d10cc3569..000000000 --- a/NBi.Testing.Core/Calculation/SinglePredicateFilterTest.cs +++ /dev/null @@ -1,303 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using NBi.Core; -using NBi.Core.Calculation; -using Moq; -using NBi.Core.Evaluate; -using NBi.Core.ResultSet; -using NBi.Core.ResultSet.Resolver; -using NBi.Core.Transformation; -using NBi.Core.Scalar.Resolver; -using NBi.Core.Calculation.Predicate; -using NBi.Core.Injection; -using NBi.Core.Variable; - -namespace NBi.Testing.Core.Calculation -{ - public class SinglePredicateFilterTest - { - - [Test] - public void Apply_Variable_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { "(null)", 10, 100 }, - new object[] { "(empty)", 2, 75 }, - new object[] { "C", 5, 50 } - })); - - var rs = service.Execute(); - - var aliases = new[] { Mock.Of(v => v.Column == 0 && v.Name == "a") }; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Text); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.NullOrEmpty); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("a")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - [Test] - public void Apply_ColumnOrdinal_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { "(null)", 10, 100 }, - new object[] { "(empty)", 2, 75 }, - new object[] { "C", 5, 50 } - })); - var rs = service.Execute(); - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Text); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.NullOrEmpty); - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(0)); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(new IColumnAlias[0], new IColumnExpression[0], predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - Assert.That(filter.Describe(), Does.Contain("null").And.Contain("or empty")); - } - - [Test] - public void Apply_ColumnName_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { "(null)", 10, 100 }, - new object[] { "(empty)", 2, 75 }, - new object[] { "C", 5, 50 } - })); - var rs = service.Execute(); - rs.Table.Columns[0].ColumnName = "first"; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Text); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.NullOrEmpty); - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("first")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(new IColumnAlias[0], new IColumnExpression[0], predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - [Test] - public void Apply_ColumnNameCaseNotMatching_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { "(null)", 10, 100 }, - new object[] { "(empty)", 2, 75 }, - new object[] { "C", 5, 50 } - })); - var rs = service.Execute(); - rs.Table.Columns[0].ColumnName = "first"; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Text); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.NullOrEmpty); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("FirSt")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(new IColumnAlias[0], new IColumnExpression[0], predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - - [Test] - public void Apply_UnexistingColumnName_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { "(null)", 10, 100 }, - new object[] { "(empty)", 2, 75 }, - new object[] { "C", 5, 50 } - })); - var rs = service.Execute(); - rs.Table.Columns[0].ColumnName = "first"; - rs.Table.Columns[1].ColumnName = "second"; - rs.Table.Columns[2].ColumnName = "third"; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Text); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.NullOrEmpty); - predicate.SetupGet(p => p.Reference).Returns(new LiteralScalarResolver(200)); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("Unexisting")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(new IColumnAlias[0], new IColumnExpression[0], predication.Object); - var ex = Assert.Throws(() => filter.Apply(rs)); - Assert.That(ex.Message, Does.Contain("first")); - Assert.That(ex.Message, Does.Contain("second")); - Assert.That(ex.Message, Does.Contain("third")); - } - - [Test] - public void Apply_NestedExpression_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { 1, 10, 100 }, - new object[] { 2, 2, 75 }, - new object[] { 3, 5, 50 } - })); - var rs = service.Execute(); - - var aliases = new List() - { - Mock.Of(v => v.Column == 0 && v.Name == "a"), - Mock.Of(v => v.Column == 1 && v.Name == "b"), - Mock.Of(v => v.Column == 2 && v.Name == "c") - }; - - var expressions = new List() - { - Mock.Of(e => e.Value == "Abs([a])+[e]" && e.Name == "d" && e.Language == LanguageType.NCalc), - Mock.Of(e => e.Value == "[b]*[c]" && e.Name == "e" && e.Language == LanguageType.NCalc) - }; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Numeric); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.MoreThanOrEqual); - predicate.SetupGet(p => p.Reference).Returns(new LiteralScalarResolver(200)); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("d")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, expressions, predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - [Test] - public void Apply_MixedExpression_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { 1, 10, 100 }, - new object[] { 2, 2, 75 }, - new object[] { 3, 5, 50 } - })); - var rs = service.Execute(); - rs.Table.Columns[2].ColumnName = "c1"; - - var aliases = new List() - { - Mock.Of(v => v.Column == 0 && v.Name == "a"), - }; - - var expressions = new List() - { - Mock.Of(e => e.Value == "Abs([a])+[e]" && e.Name == "d" && e.Language == LanguageType.NCalc), - Mock.Of(e => e.Value == "[#1]*[c1]" && e.Name == "e" && e.Language == LanguageType.NCalc) - }; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Numeric); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.MoreThanOrEqual); - predicate.SetupGet(p => p.Reference).Returns(new LiteralScalarResolver(200)); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("d")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, expressions, predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - [Test] - public void Apply_NativeExpression_CorrectResult() - { - var service = new ObjectsResultSetResolver( - new ObjectsResultSetResolverArgs( - new [] - { - new object[] { new DateTime(2019, 10, 01, 8, 0, 0), 10, 100 }, - new object[] { new DateTime(2019, 10, 01, 23, 0, 0), 2, 75 }, - new object[] { new DateTime(2019, 10, 02, 05, 0, 0), 5, 50 } - })); - var rs = service.Execute(); - rs.Table.Columns[0].ColumnName = "a"; - - var aliases = new List() - { - Mock.Of(v => v.Column == 0 && v.Name == "x"), - }; - - var expressions = new List() - { - Mock.Of( - e => e.Value == "a | utc-to-local(Brussels) | dateTime-to-date" - && e.Name == "d" - && e.Language == LanguageType.Native - && e.Type==ColumnType.DateTime), - }; - - var predicate = new Mock(); - predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.DateTime); - predicate.SetupGet(p => p.ComparerType).Returns(ComparerType.MoreThanOrEqual); - predicate.SetupGet(p => p.Reference).Returns(new LiteralScalarResolver(new DateTime(2019, 10, 2))); - - var predication = new Mock(); - predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("d")); - predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - - - var factory = new ResultSetFilterFactory(new ServiceLocator(), new Context(null)); - var filter = factory.Instantiate(aliases, expressions, predication.Object); - var result = filter.Apply(rs); - - Assert.That(result.Rows, Has.Count.EqualTo(2)); - } - - } -} diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index c76983a3f..e23ca2ef3 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -102,18 +102,20 @@ - - - - - + + + + + + + + - diff --git a/NBi.Testing.Core/Calculation/FilterGroupByFilterTest.cs b/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs similarity index 87% rename from NBi.Testing.Core/Calculation/FilterGroupByFilterTest.cs rename to NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs index 0d451157a..66c5e16ab 100644 --- a/NBi.Testing.Core/Calculation/FilterGroupByFilterTest.cs +++ b/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs @@ -1,9 +1,12 @@ using NBi.Core.Calculation; using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.Calculation.Ranking; using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Filtering; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Comparer; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -13,9 +16,9 @@ using System.Threading.Tasks; using static NBi.Core.ResultSet.SettingsOrdinalResultSet; -namespace NBi.Testing.Core.Calculation +namespace NBi.Testing.Core.ResultSet.Filtering { - public class FilterGroupByFilterTest + public class GroupByFilterTest { [Test] public void Execute_Top2OneKey_ResultSetReduced() @@ -29,7 +32,7 @@ public void Execute_Top2OneKey_ResultSetReduced() var filter = new TopRanking(2, new ColumnOrdinalIdentifier(1), ColumnType.Numeric); - var rankingByGroup = new FilterGroupByFilter(filter, grouping); + var rankingByGroup = new GroupByFilter(filter, grouping); var result = rankingByGroup.Apply(rs); Assert.That(result.Table.Rows, Has.Count.EqualTo(3)); @@ -46,7 +49,7 @@ public void Execute_Top2None_ResultSetReduced() var filter = new TopRanking(2, new ColumnOrdinalIdentifier(1), ColumnType.Numeric); - var rankingByGroup = new FilterGroupByFilter(filter, new NoneGrouping()); + var rankingByGroup = new GroupByFilter(filter, new NoneGrouping()); var result = rankingByGroup.Apply(rs); Assert.That(result.Table.Rows, Has.Count.EqualTo(2)); diff --git a/NBi.Testing.Core/Calculation/CombinationPredicateFilterTest.cs b/NBi.Testing.Core/ResultSet/Filtering/PredicationFilterTest.cs similarity index 87% rename from NBi.Testing.Core/Calculation/CombinationPredicateFilterTest.cs rename to NBi.Testing.Core/ResultSet/Filtering/PredicationFilterTest.cs index a683db392..1131401e1 100644 --- a/NBi.Testing.Core/Calculation/CombinationPredicateFilterTest.cs +++ b/NBi.Testing.Core/ResultSet/Filtering/PredicationFilterTest.cs @@ -13,10 +13,11 @@ using NBi.Core.Scalar.Resolver; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; -namespace NBi.Testing.Core.Calculation +namespace NBi.Testing.Core.ResultSet.Filtering { - public class CombinationPredicateFilterTest + public class PredicationFilterTest { [Test] @@ -52,10 +53,10 @@ public void Apply_And_CorrectResult() var predication2 = new Mock(); predication2.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication2.SetupGet(p => p.Predicate).Returns(predicate2.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], CombinationOperator.And , new[] { predication1.Object, predication2.Object }); + + var factory = new ResultSetFilterFactory(null); + var filter = factory.Instantiate(CombinationOperator.And, new[] { predication1.Object, predication2.Object }, new Context(null, aliases, Array.Empty())); var result = filter.Apply(rs); Assert.That(result.Rows, Has.Count.EqualTo(2)); @@ -96,8 +97,8 @@ public void Apply_AndWillNotEvaluateAll_CorrectResult() predication2.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(0)); predication2.SetupGet(p => p.Predicate).Returns(predicate2.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], CombinationOperator.And, new[] { predication1.Object, predication2.Object }); + var factory = new ResultSetFilterFactory(null); + var filter = factory.Instantiate(CombinationOperator.And, new[] { predication1.Object, predication2.Object }, new Context(null, aliases, Array.Empty())); var result = filter.Apply(rs); Assert.That(result.Rows, Has.Count.EqualTo(1)); @@ -135,10 +136,10 @@ public void Apply_Or_CorrectResult() var predication2 = new Mock(); predication2.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication2.SetupGet(p => p.Predicate).Returns(predicate2.Object); - - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], CombinationOperator.Or, new[] { predication1.Object, predication2.Object }); + + var factory = new ResultSetFilterFactory(null); + var filter = factory.Instantiate(CombinationOperator.Or, new[] { predication1.Object, predication2.Object }, new Context(null, aliases, Array.Empty())); var result = filter.Apply(rs); Assert.That(result.Rows, Has.Count.EqualTo(4)); @@ -177,8 +178,8 @@ public void Apply_OrWillNotEvaluateAll_CorrectResult() predication2.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(0)); predication2.SetupGet(p => p.Predicate).Returns(predicate2.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], CombinationOperator.Or, new[] { predication1.Object, predication2.Object }); + var factory = new ResultSetFilterFactory(null); + var filter = factory.Instantiate(CombinationOperator.Or, new[] { predication1.Object, predication2.Object }, new Context(null, aliases, Array.Empty())); var result = filter.Apply(rs); Assert.That(result.Rows, Has.Count.EqualTo(3)); @@ -217,8 +218,8 @@ public void Apply_XOr_CorrectResult() predication2.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication2.SetupGet(p => p.Predicate).Returns(predicate1.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); - var filter = factory.Instantiate(aliases, new IColumnExpression[0], CombinationOperator.XOr, new[] { predication1.Object, predication2.Object }); + var factory = new ResultSetFilterFactory(null); + var filter = factory.Instantiate(CombinationOperator.XOr, new[] { predication1.Object, predication2.Object }, new Context(null, aliases, Array.Empty())); var result = filter.Apply(rs); Assert.That(result.Rows, Has.Count.EqualTo(3)); diff --git a/NBi.Testing.Core/Scalar/Resolver/ContextScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/ContextScalarResolverTest.cs index 4af1ac98c..d4034dce6 100644 --- a/NBi.Testing.Core/Scalar/Resolver/ContextScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/ContextScalarResolverTest.cs @@ -21,7 +21,7 @@ public void Execute_FirstRowByName_CorrectEvaluation() rs.Load(new[] { new object[] { "a", 1 }, new object[] { "b", 2 } }); rs.Columns[0].ColumnName = "Foo"; - var context = new Context(null); + var context = Context.None; var args = new ContextScalarResolverArgs(context, new ColumnNameIdentifier("Foo")); var resolver = new ContextScalarResolver(args); @@ -35,7 +35,7 @@ public void Execute_FirstRowByOrdinal_CorrectEvaluation() var rs = new NBi.Core.ResultSet.ResultSet(); rs.Load(new[] { new object[] { "a", 1 }, new object[] { "b", 2 } }); - var context = new Context(null); + var context = Context.None; var args = new ContextScalarResolverArgs(context, new ColumnOrdinalIdentifier(0)); var resolver = new ContextScalarResolver(args); @@ -50,7 +50,7 @@ public void Execute_SecondRow_CorrectEvaluation() rs.Load(new[] { new object[] { "a", 1 }, new object[] { "b", 2 } }); rs.Columns[0].ColumnName = "Foo"; - var context = new Context(null); + var context = Context.None; var args = new ContextScalarResolverArgs(context, new ColumnNameIdentifier("Foo")); var resolver = new ContextScalarResolver(args); diff --git a/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs b/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs index e35646ae2..9c9450405 100644 --- a/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs @@ -45,7 +45,7 @@ public void Instantiate_ContextArgs_ContextResolver() { using (var dt = new DataTable()) { - var context = new Context(null); + var context = Context.None; context.Switch(dt.NewRow()); var args = new ContextScalarResolverArgs(context, new ColumnOrdinalIdentifier(0)); diff --git a/NBi.Testing.Core/Transformation/TransformationProviderTest.cs b/NBi.Testing.Core/Transformation/TransformationProviderTest.cs index a5c30f3ee..d3aa02f68 100644 --- a/NBi.Testing.Core/Transformation/TransformationProviderTest.cs +++ b/NBi.Testing.Core/Transformation/TransformationProviderTest.cs @@ -31,7 +31,7 @@ public void Transform_SimpleTranformation_CorrectHandlingOfColumnNames() && t.Code == "value.Substring(0,1)" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); @@ -53,7 +53,7 @@ public void Transform_SimpleTranformation_Correct() && t.Code == "value.Substring(0,1)" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); @@ -73,7 +73,7 @@ public void Transform_NativeTranformationTrim_Correct() && t.Code == "text-to-trim" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); @@ -93,7 +93,7 @@ public void Transform_NativeTranformationFirstCharWithContext_Correct() && t.Code == "text-to-first-chars(#1)" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); @@ -114,7 +114,7 @@ public void Transform_NativeTranformationBlankToNull_Correct() && t.Code == "blank-to-null" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); @@ -154,7 +154,7 @@ public void Transform_TypeSwitch_Correct() && t.Code == "value.Month + (value.Year-2000)*12" ); - var provider = new TransformationProvider(new ServiceLocator(), new Context(null)); + var provider = new TransformationProvider(new ServiceLocator(), Context.None); provider.Add(new ColumnOrdinalIdentifier(0), transformation); provider.Transform(resultSet); diff --git a/NBi.Testing/Unit/NUnit/Builder/Helper/PredicateArgsBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/Helper/PredicateArgsBuilderTest.cs index f66e1d37c..d4bf258be 100644 --- a/NBi.Testing/Unit/NUnit/Builder/Helper/PredicateArgsBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/Helper/PredicateArgsBuilderTest.cs @@ -23,7 +23,7 @@ public void Build_VariableAndFunctions_FunctionScalarResolverArgs() Reference = "#12 | text-to-upper | text-to-first-chars([ColA])" }; - var builder = new PredicateArgsBuilder(new ServiceLocator(), new Context(null)); + var builder = new PredicateArgsBuilder(new ServiceLocator(), Context.None); var args = builder.Execute(Core.ResultSet.ColumnType.Text, predicateXml); Assert.That(args, Is.AssignableTo()); diff --git a/NBi.Testing/Unit/NUnit/Builder/Helper/ScalarResolverArgsBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/Helper/ScalarResolverArgsBuilderTest.cs index 43213ad97..572ca0438 100644 --- a/NBi.Testing/Unit/NUnit/Builder/Helper/ScalarResolverArgsBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/Helper/ScalarResolverArgsBuilderTest.cs @@ -43,7 +43,7 @@ public void Build_Variable_GlobalVariableScalarResolverArgs() [Test] public void Build_ContextColumnName_ContextScalarResolverArgs() { - var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), new Context(null)); + var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), Context.None); builder.Setup("[ColA]"); builder.Build(); var args = builder.GetArgs(); @@ -53,7 +53,7 @@ public void Build_ContextColumnName_ContextScalarResolverArgs() [Test] public void Build_ContextColumnOrdinal_ContextScalarResolverArgs() { - var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), new Context(null)); + var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), Context.None); builder.Setup("#12"); builder.Build(); var args = builder.GetArgs(); @@ -63,7 +63,7 @@ public void Build_ContextColumnOrdinal_ContextScalarResolverArgs() [Test] public void Build_ContextColumnOrdinalFollowedByNativeTransformations_ContextScalarResolverArgs() { - var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), new Context(null)); + var builder = new ScalarResolverArgsBuilder(new ServiceLocator(), Context.None); builder.Setup("#12 | text-to-upper | text-to-first-chars([ColA])"); builder.Build(); var args = builder.GetArgs(); diff --git a/NBi.Testing/Unit/NUnit/ResultSetComparison/AllRowsConstraintTest.cs b/NBi.Testing/Unit/NUnit/ResultSetComparison/AllRowsConstraintTest.cs index 9178a0965..1b104e41a 100644 --- a/NBi.Testing/Unit/NUnit/ResultSetComparison/AllRowsConstraintTest.cs +++ b/NBi.Testing/Unit/NUnit/ResultSetComparison/AllRowsConstraintTest.cs @@ -14,6 +14,7 @@ using NBi.Core.Scalar.Resolver; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.Testing.Unit.NUnit.ResultSetComparison { @@ -57,12 +58,11 @@ public void Matches_ResultSetService_CallToExecuteOnce() predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("Value")); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate - ( - new List() { alias } - , new List() { } - , predication.Object + ( + predication.Object + , new Context(null, new List() { alias }, Array.Empty()) ); var rowCount = new AllRowsConstraint(filter); @@ -89,12 +89,11 @@ public void Matches_AllValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new AllRowsConstraint(filter); @@ -116,12 +115,11 @@ public void Matches_NoneValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new AllRowsConstraint(filter); @@ -143,12 +141,11 @@ public void Matches_FewValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new AllRowsConstraint(filter); @@ -170,12 +167,11 @@ public void Matches_SingleValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new AllRowsConstraint(filter); diff --git a/NBi.Testing/Unit/NUnit/ResultSetComparison/NoRowsConstraintTest.cs b/NBi.Testing/Unit/NUnit/ResultSetComparison/NoRowsConstraintTest.cs index 38b9f04c3..0d66e3e37 100644 --- a/NBi.Testing/Unit/NUnit/ResultSetComparison/NoRowsConstraintTest.cs +++ b/NBi.Testing/Unit/NUnit/ResultSetComparison/NoRowsConstraintTest.cs @@ -1,19 +1,16 @@ using System; using System.Linq; using Moq; -using NBi.Core; using NBi.NUnit.Query; using NBi.Core.ResultSet; -using System.Data.SqlClient; -using NUnitCtr = NUnit.Framework.Constraints; using NBi.Core.Calculation; using NBi.Core.Evaluate; using System.Collections.Generic; using NUnit.Framework; -using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.Testing.Unit.NUnit.ResultSetComparison { @@ -58,12 +55,11 @@ public void Matches_ResultSetService_CallToExecuteOnce() predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("Value")); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() { alias } - , new List() { } - , predication.Object + predication.Object + , new Context(null, new List() { alias }, Array.Empty()) ); var rowCount = new NoRowsConstraint(filter); @@ -90,12 +86,11 @@ public void Matches_AllValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new NoRowsConstraint(filter); @@ -117,12 +112,11 @@ public void Matches_NoneValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new NoRowsConstraint(filter); @@ -144,12 +138,11 @@ public void Matches_FewValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new NoRowsConstraint(filter); @@ -171,12 +164,11 @@ public void Matches_SingleValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new NoRowsConstraint(filter); diff --git a/NBi.Testing/Unit/NUnit/ResultSetComparison/SingleRowConstraintTest.cs b/NBi.Testing/Unit/NUnit/ResultSetComparison/SingleRowConstraintTest.cs index 1af457462..fd615932e 100644 --- a/NBi.Testing/Unit/NUnit/ResultSetComparison/SingleRowConstraintTest.cs +++ b/NBi.Testing/Unit/NUnit/ResultSetComparison/SingleRowConstraintTest.cs @@ -1,19 +1,16 @@ using System; using System.Linq; using Moq; -using NBi.Core; using NBi.NUnit.Query; using NBi.Core.ResultSet; -using System.Data.SqlClient; -using NUnitCtr = NUnit.Framework.Constraints; using NBi.Core.Calculation; using NBi.Core.Evaluate; using System.Collections.Generic; using NUnit.Framework; -using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.Testing.Unit.NUnit.ResultSetComparison { @@ -59,12 +56,11 @@ public void Matches_ResultSetService_CallToExecuteOnce() predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("Value")); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() { alias } - , new List() { } - , predication.Object + predication.Object + , new Context(null, new List() { alias }, Array.Empty()) ); var singleRowCtr = new SingleRowConstraint(filter); @@ -92,12 +88,11 @@ public void Matches_AllValidatePredicate_False() predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new SingleRowConstraint(filter); @@ -119,12 +114,11 @@ public void Matches_NoneValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new SingleRowConstraint(filter); @@ -146,12 +140,11 @@ public void Matches_FewValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new SingleRowConstraint(filter); @@ -173,12 +166,11 @@ public void Matches_SingleValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var singleRowCtr = new SingleRowConstraint(filter); diff --git a/NBi.Testing/Unit/NUnit/ResultSetComparison/SomeRowsConstraintTest.cs b/NBi.Testing/Unit/NUnit/ResultSetComparison/SomeRowsConstraintTest.cs index 37e782c11..f7c3ab370 100644 --- a/NBi.Testing/Unit/NUnit/ResultSetComparison/SomeRowsConstraintTest.cs +++ b/NBi.Testing/Unit/NUnit/ResultSetComparison/SomeRowsConstraintTest.cs @@ -1,32 +1,29 @@ using System; using System.Linq; using Moq; -using NBi.Core; using NBi.NUnit.Query; using NBi.Core.ResultSet; -using System.Data.SqlClient; -using NUnitCtr = NUnit.Framework.Constraints; using NBi.Core.Calculation; using NBi.Core.Evaluate; using System.Collections.Generic; using NUnit.Framework; -using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; using NBi.Core.Calculation.Predicate; using NBi.Core.Variable; +using NBi.Core.ResultSet.Filtering; namespace NBi.Testing.Unit.NUnit.ResultSetComparison { [TestFixture] public class SomeRowsConstraintTest { - + #region Setup & Teardown [SetUp] public void SetUp() { - + } [TearDown] @@ -57,12 +54,11 @@ public void Matches_ResultSetService_CallToExecuteOnce() predication.SetupGet(p => p.Identifier).Returns(new ColumnNameIdentifier("Value")); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() { alias } - , new List() { } - , predication.Object + predication.Object + , new Context(null, new List() { alias }, Array.Empty()) ); var someRowCtr = new SomeRowsConstraint(filter); @@ -78,7 +74,7 @@ public void Matches_ResultSetService_CallToExecuteOnce() public void Matches_AllValidatePredicate_True() { var rs = new ResultSet(); - rs.Load(new[] { new object[] {"a", -1}, new object[] { "b", -2 }, new object[] { "c", -3 } }); + rs.Load(new[] { new object[] { "a", -1 }, new object[] { "b", -2 }, new object[] { "c", -3 } }); var predicate = new Mock(); predicate.SetupGet(p => p.ColumnType).Returns(ColumnType.Numeric); @@ -89,12 +85,11 @@ public void Matches_AllValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var someRowCtr = new SomeRowsConstraint(filter); @@ -116,12 +111,11 @@ public void Matches_NoneValidatePredicate_False() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var someRowCtr = new SomeRowsConstraint(filter); @@ -143,12 +137,11 @@ public void Matches_FewValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var someRowCtr = new SomeRowsConstraint(filter); @@ -170,12 +163,11 @@ public void Matches_SingleValidatePredicate_True() predication.SetupGet(p => p.Identifier).Returns(new ColumnOrdinalIdentifier(1)); predication.SetupGet(p => p.Predicate).Returns(predicate.Object); - var factory = new ResultSetFilterFactory(null, new Context(null)); + var factory = new ResultSetFilterFactory(null); var filter = factory.Instantiate ( - new List() - , new List() - , predication.Object + predication.Object + , Context.None ); var someRowCtr = new SomeRowsConstraint(filter); From 691bf1e905367f770d21a67ea7517da4f63755be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Thu, 14 Nov 2019 02:09:48 +0100 Subject: [PATCH 25/57] Add CaseGroupBy --- .../Grouping/CaseBased/CaseGroupByArgs.cs | 16 ++++ .../Grouping/CaseBased/CaseGrouping.cs | 44 ++++++++++ .../Grouping/CaseBased/GroupByCase.cs | 42 ---------- .../Grouping/ColumnBased/ColumnGroupByArgs.cs | 20 +++++ ...tByColumnGrouping.cs => ColumnGrouping.cs} | 11 +-- ...olumnGrouping.cs => NameColumnGrouping.cs} | 7 +- ...mnGrouping.cs => OrdinalColumnGrouping.cs} | 7 +- .../Calculation/Grouping/GroupByFactory.cs | 23 +++-- NBi.Core/Calculation/Grouping/IGroupByArgs.cs | 11 +++ NBi.Core/Calculation/SinglePredicateFilter.cs | 40 --------- NBi.Core/NBi.Core.csproj | 12 +-- .../Alteration/Reshaping/UnstackEngine.cs | 4 +- .../Summarization/SummarizeEngine.cs | 4 +- NBi.Core/ResultSet/Filtering/NoneFilter.cs | 11 +-- .../Filtering/ResultSetFilterFactory.cs | 4 +- .../Grouping/CaseBased/CaseGroupingTest.cs | 83 +++++++++++++++++++ ...upingTest.cs => NameColumnGroupingTest.cs} | 9 +- ...ngTest.cs => OrdinalColumnGroupingTest.cs} | 9 +- NBi.Testing.Core/NBi.Testing.Core.csproj | 5 +- .../ResultSet/Filtering/GroupByFilterTest.cs | 2 +- 20 files changed, 238 insertions(+), 126 deletions(-) create mode 100644 NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs create mode 100644 NBi.Core/Calculation/Grouping/CaseBased/CaseGrouping.cs delete mode 100644 NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs create mode 100644 NBi.Core/Calculation/Grouping/ColumnBased/ColumnGroupByArgs.cs rename NBi.Core/Calculation/Grouping/ColumnBased/{AbstractByColumnGrouping.cs => ColumnGrouping.cs} (81%) rename NBi.Core/Calculation/Grouping/ColumnBased/{NameByColumnGrouping.cs => NameColumnGrouping.cs} (71%) rename NBi.Core/Calculation/Grouping/ColumnBased/{OrdinalByColumnGrouping.cs => OrdinalColumnGrouping.cs} (71%) create mode 100644 NBi.Core/Calculation/Grouping/IGroupByArgs.cs delete mode 100644 NBi.Core/Calculation/SinglePredicateFilter.cs create mode 100644 NBi.Testing.Core/Calculation/Grouping/CaseBased/CaseGroupingTest.cs rename NBi.Testing.Core/Calculation/Grouping/ColumnBased/{NameByColumnGroupingTest.cs => NameColumnGroupingTest.cs} (93%) rename NBi.Testing.Core/Calculation/Grouping/ColumnBased/{OrdinalByColumnGroupingTest.cs => OrdinalColumnGroupingTest.cs} (91%) diff --git a/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs b/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs new file mode 100644 index 000000000..be6c06ff0 --- /dev/null +++ b/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs @@ -0,0 +1,16 @@ +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping.CaseBased +{ + public class CaseGroupByArgs : IGroupByArgs + { + public IEnumerable Cases { get; set; } + public Context Context { get; set; } + } +} diff --git a/NBi.Core/Calculation/Grouping/CaseBased/CaseGrouping.cs b/NBi.Core/Calculation/Grouping/CaseBased/CaseGrouping.cs new file mode 100644 index 000000000..8f9628425 --- /dev/null +++ b/NBi.Core/Calculation/Grouping/CaseBased/CaseGrouping.cs @@ -0,0 +1,44 @@ +using NBi.Core.Calculation.Predication; +using NBi.Core.Variable; +using NBi.Extensibility; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping.CaseBased +{ + class CaseGrouping : IGroupBy + { + protected IEnumerable Cases { get; } + protected Context Context { get; } + + public CaseGrouping(IEnumerable cases, Context context) + => (Cases, Context) = (cases, context); + + public IDictionary Execute(ResultSet.ResultSet resultSet) + { + var stopWatch = new Stopwatch(); + var dico = new Dictionary(); + stopWatch.Start(); + + foreach (DataRow row in resultSet.Rows) + { + Context.Switch(row); + var index = Cases.Select((p, i) => new { Predication = p, Index = i }) + .FirstOrDefault(x => x.Predication.Execute(Context)) + ?.Index ?? -1; + var key = new ResultSet.KeyCollection(new object[] { index }); + if (!dico.ContainsKey(key)) + dico.Add(key, row.Table.Clone()); + dico[key].ImportRow(row); + } + + Trace.WriteLineIf(NBiTraceSwitch.TraceInfo, $"Building rows' groups by cases: {dico.Count} [{stopWatch.Elapsed.ToString(@"d\d\.hh\h\:mm\m\:ss\s\ \+fff\m\s")}"); + return dico; + } + } +} diff --git a/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs b/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs deleted file mode 100644 index baaaf92c8..000000000 --- a/NBi.Core/Calculation/Grouping/CaseBased/GroupByCase.cs +++ /dev/null @@ -1,42 +0,0 @@ -using NBi.Core.Calculation.Predication; -using NBi.Core.Variable; -using NBi.Extensibility; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Calculation.Grouping.CaseBased -{ - class GroupByCase - { - protected IEnumerable Cases { get; } - - public GroupByCase(IEnumerable cases) - => Cases = cases; - - public IDictionary Execute(ResultSet.ResultSet resultSet, Context context) - { - var stopWatch = new Stopwatch(); - var dico = new Dictionary(); - stopWatch.Start(); - - foreach (DataRow row in resultSet.Rows) - { - context.Switch(row); - var predication = Cases.FirstOrDefault(p => p.Execute(context)); - - if (!dico.ContainsKey(predication)) - dico.Add(predication, row.Table.Clone()); - dico[predication].ImportRow(row); - } - - Trace.WriteLineIf(NBiTraceSwitch.TraceInfo, $"Building rows' groups by cases: {dico.Count} [{stopWatch.Elapsed.ToString(@"d\d\.hh\h\:mm\m\:ss\s\ \+fff\m\s")}"); - return dico; - - } - } -} diff --git a/NBi.Core/Calculation/Grouping/ColumnBased/ColumnGroupByArgs.cs b/NBi.Core/Calculation/Grouping/ColumnBased/ColumnGroupByArgs.cs new file mode 100644 index 000000000..2315b873b --- /dev/null +++ b/NBi.Core/Calculation/Grouping/ColumnBased/ColumnGroupByArgs.cs @@ -0,0 +1,20 @@ +using NBi.Core.ResultSet; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping.ColumnBased +{ + public class ColumnGroupByArgs : IGroupByArgs + { + + public IEnumerable Columns { get; set; } + public Context Context { get; set; } + + public ColumnGroupByArgs(IEnumerable columns, Context context) + => (Columns, Context) = (columns, context); + } +} diff --git a/NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/ColumnGrouping.cs similarity index 81% rename from NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/ColumnGrouping.cs index a1ad0a825..058befa36 100644 --- a/NBi.Core/Calculation/Grouping/ColumnBased/AbstractByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/ColumnGrouping.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Core.Variable; using NBi.Extensibility; using System; using System.Collections.Generic; @@ -10,14 +11,13 @@ namespace NBi.Core.Calculation.Grouping.ColumnBased { - public abstract class AbstractByColumnGrouping : IGroupBy + public abstract class ColumnGrouping : IGroupBy { protected ISettingsResultSet Settings { get; } + protected Context Context { get; } - public AbstractByColumnGrouping(ISettingsResultSet settings) - { - Settings = settings; - } + protected ColumnGrouping(ISettingsResultSet settings, Context context) + => (Settings, Context) = (settings, context); public IDictionary Execute(ResultSet.ResultSet resultSet) { @@ -28,6 +28,7 @@ public IDictionary Execute(ResultSet.ResultSet resultS stopWatch.Start(); foreach (DataRow row in resultSet.Rows) { + Context.Switch(row); var key = keyComparer.GetKeys(row); if (!dico.ContainsKey(key)) dico.Add(key, row.Table.Clone()); diff --git a/NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/NameColumnGrouping.cs similarity index 71% rename from NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/NameColumnGrouping.cs index d82d0b280..b73a11c00 100644 --- a/NBi.Core/Calculation/Grouping/ColumnBased/NameByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/NameColumnGrouping.cs @@ -5,15 +5,16 @@ using System.Text; using System.Threading.Tasks; using NBi.Core.ResultSet; +using NBi.Core.Variable; namespace NBi.Core.Calculation.Grouping.ColumnBased { - class NameByColumnGrouping : AbstractByColumnGrouping + class NameColumnGrouping : ColumnGrouping { protected new SettingsNameResultSet Settings { get => base.Settings as SettingsNameResultSet; } - public NameByColumnGrouping(SettingsNameResultSet settings) - : base(settings) { } + public NameColumnGrouping(SettingsNameResultSet settings, Context context) + : base(settings, context) { } protected override DataRowKeysComparer BuildDataRowsKeyComparer(DataTable x) => new DataRowKeysComparerByName(Settings); diff --git a/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs b/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGrouping.cs similarity index 71% rename from NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs rename to NBi.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGrouping.cs index f811ac84b..fa505fb52 100644 --- a/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGrouping.cs +++ b/NBi.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGrouping.cs @@ -5,15 +5,16 @@ using System.Text; using System.Threading.Tasks; using NBi.Core.ResultSet; +using NBi.Core.Variable; namespace NBi.Core.Calculation.Grouping.ColumnBased { - class OrdinalByColumnGrouping : AbstractByColumnGrouping + class OrdinalColumnGrouping : ColumnGrouping { protected new SettingsOrdinalResultSet Settings { get => base.Settings as SettingsOrdinalResultSet; } - public OrdinalByColumnGrouping(SettingsOrdinalResultSet settings) - : base(settings) { } + public OrdinalColumnGrouping(SettingsOrdinalResultSet settings, Context context) + : base(settings, context) { } protected override DataRowKeysComparer BuildDataRowsKeyComparer(DataTable x) => new DataRowKeysComparerByOrdinal(Settings, x.Columns.Count); diff --git a/NBi.Core/Calculation/Grouping/GroupByFactory.cs b/NBi.Core/Calculation/Grouping/GroupByFactory.cs index 933d0c4c9..d167f2ab9 100644 --- a/NBi.Core/Calculation/Grouping/GroupByFactory.cs +++ b/NBi.Core/Calculation/Grouping/GroupByFactory.cs @@ -1,8 +1,11 @@ -using NBi.Core.Calculation.Grouping.ColumnBased; +using NBi.Core.Calculation.Grouping.CaseBased; +using NBi.Core.Calculation.Grouping.ColumnBased; +using NBi.Core.Calculation.Predication; using NBi.Core.ResultSet; using NBi.Core.ResultSet.Equivalence; using NBi.Core.Scalar.Comparer; using NBi.Core.Transformation; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Linq; @@ -14,9 +17,19 @@ namespace NBi.Core.Calculation.Grouping { public class GroupByFactory { - public IGroupBy None() => new NoneGrouping(); + public static IGroupBy None() => new NoneGrouping(); - public IGroupBy Instantiate(IEnumerable columns) + public IGroupBy Instantiate(IGroupByArgs args) + { + switch (args) + { + case ColumnGroupByArgs x: return Instantiate(x.Columns, x.Context); + case CaseGroupByArgs x: return new CaseGrouping(x.Cases, x.Context); + default: throw new ArgumentOutOfRangeException(); + } + } + + private IGroupBy Instantiate(IEnumerable columns, Context context) { if ((columns?.Count() ?? 0) == 0) return new NoneGrouping(); @@ -39,10 +52,10 @@ public IGroupBy Instantiate(IEnumerable columns) var settings = builder.GetSettings(); if (settings is SettingsOrdinalResultSet) - return new OrdinalByColumnGrouping(settings as SettingsOrdinalResultSet); + return new OrdinalColumnGrouping(settings as SettingsOrdinalResultSet, context); else if (settings is SettingsNameResultSet) - return new NameByColumnGrouping(settings as SettingsNameResultSet); + return new NameColumnGrouping(settings as SettingsNameResultSet, context); throw new ArgumentOutOfRangeException(nameof(settings)); } diff --git a/NBi.Core/Calculation/Grouping/IGroupByArgs.cs b/NBi.Core/Calculation/Grouping/IGroupByArgs.cs new file mode 100644 index 000000000..779d85c96 --- /dev/null +++ b/NBi.Core/Calculation/Grouping/IGroupByArgs.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping +{ + public interface IGroupByArgs + { } +} diff --git a/NBi.Core/Calculation/SinglePredicateFilter.cs b/NBi.Core/Calculation/SinglePredicateFilter.cs deleted file mode 100644 index 599bbbd86..000000000 --- a/NBi.Core/Calculation/SinglePredicateFilter.cs +++ /dev/null @@ -1,40 +0,0 @@ -//using NBi.Core.Calculation.Predicate; -//using NBi.Core.Evaluate; -//using NBi.Core.Injection; -//using NBi.Core.ResultSet; -//using NBi.Core.Variable; -//using System; -//using System.Collections.Generic; -//using System.Data; -//using System.Linq; -//using System.Text; -//using System.Threading.Tasks; - -//namespace NBi.Core.Calculation -//{ -// class SinglePredicateFilter : RowValueExtractor -// { -// private readonly Func implementation; -// private readonly IColumnIdentifier operand; -// private readonly Func describeFunction; - -// public SinglePredicateFilter(ServiceLocator serviceLocator, Context context, IEnumerable aliases, IEnumerable expressions, IColumnIdentifier operand, Func implementation, Func describeFunction) -// : base(serviceLocator, context, aliases, expressions) -// { -// this.operand = operand; -// this.implementation = implementation; -// this.describeFunction = describeFunction; -// } - -// protected override bool RowApply(Context context) -// { -// var value = GetValueFromRow(context, operand); -// return implementation(value); -// } - -// public override string Describe() -// { -// return $"{operand.Label} {describeFunction()}."; -// } -// } -//} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index ca659aa92..70a68c095 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -145,19 +145,22 @@ + + + - + - + - - + + @@ -224,7 +227,6 @@ - diff --git a/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs b/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs index 64ae7e27c..e3920e5bb 100644 --- a/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Reshaping/UnstackEngine.cs @@ -1,6 +1,8 @@ using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.Scalar.Resolver; using NBi.Core.Sequence.Transformation.Aggregation; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Data; @@ -48,7 +50,7 @@ public ResultSet Execute(ResultSet rs) var groupbyFactory = new GroupByFactory(); - var groupbyEngine = groupbyFactory.Instantiate(Args.GroupBys); + var groupbyEngine = groupbyFactory.Instantiate(new ColumnGroupByArgs(Args.GroupBys, Context.None)); var groups = groupbyEngine.Execute(rs); foreach (var group in groups) { diff --git a/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs b/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs index 90af3014e..86b1d4078 100644 --- a/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Summarization/SummarizeEngine.cs @@ -1,6 +1,8 @@ using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.Scalar.Resolver; using NBi.Core.Sequence.Transformation.Aggregation; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Data; @@ -42,7 +44,7 @@ public ResultSet Execute(ResultSet rs) } var groupbyFactory = new GroupByFactory(); - var groupbyEngine = groupbyFactory.Instantiate(Args.GroupBys); + var groupbyEngine = groupbyFactory.Instantiate(new ColumnGroupByArgs(Args.GroupBys, Context.None)); var groups = groupbyEngine.Execute(rs); foreach (var group in groups) { diff --git a/NBi.Core/ResultSet/Filtering/NoneFilter.cs b/NBi.Core/ResultSet/Filtering/NoneFilter.cs index 7395183d6..6c31dda0f 100644 --- a/NBi.Core/ResultSet/Filtering/NoneFilter.cs +++ b/NBi.Core/ResultSet/Filtering/NoneFilter.cs @@ -10,19 +10,12 @@ namespace NBi.Core.ResultSet.Filtering class NoneFilter : IResultSetFilter { public ResultSet Apply(ResultSet rs) - { - if (rs == null) - throw new ArgumentNullException(); - return rs; - } + => rs ?? throw new ArgumentNullException(); public ResultSet AntiApply(ResultSet rs) { - if (rs == null) - throw new ArgumentNullException(); - + var table = rs?.Table?.Clone() ?? throw new ArgumentNullException(); var filteredRs = new ResultSet(); - var table = rs.Table.Clone(); filteredRs.Load(table); return filteredRs; } diff --git a/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs index 850b891ef..8059bed94 100644 --- a/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs +++ b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs @@ -1,5 +1,6 @@ using NBi.Core.Calculation; using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.Calculation.Predicate; using NBi.Core.Calculation.Predicate.Combination; using NBi.Core.Calculation.Predication; @@ -65,7 +66,8 @@ public IResultSetFilter Instantiate(CombinationOperator combinationOperator, IEn public IResultSetFilter Instantiate(IRankingInfo rankingInfo, IEnumerable columns) { var groupingFactory = new GroupByFactory(); - var grouping = groupingFactory.Instantiate(columns); + var groupingArgs = new ColumnGroupByArgs(columns, Context.None); + var grouping = groupingFactory.Instantiate(groupingArgs); var rankingFactory = new RankingFactory(); var ranking = rankingFactory.Instantiate(rankingInfo); diff --git a/NBi.Testing.Core/Calculation/Grouping/CaseBased/CaseGroupingTest.cs b/NBi.Testing.Core/Calculation/Grouping/CaseBased/CaseGroupingTest.cs new file mode 100644 index 000000000..ebec9915d --- /dev/null +++ b/NBi.Testing.Core/Calculation/Grouping/CaseBased/CaseGroupingTest.cs @@ -0,0 +1,83 @@ +using NBi.Core.Calculation.Grouping.CaseBased; +using NBi.Core.Calculation.Predicate.Text; +using NBi.Core.Calculation.Predication; +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Resolver; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Calculation.Grouping.ColumnBased +{ + public class CaseGroupingTest + { + [Test] + public void Execute_SingleColumn_TwoGroups() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "alpha", 1 }, new object[] { "beta", 2 }, new object[] { "BETA", 3 }, new object[] { "alpha", 4 } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + var lowerCase = new SinglePredication(new TextLowerCase(false), new ColumnOrdinalIdentifier(0)); + var upperCase = new SinglePredication(new TextUpperCase(false), new ColumnOrdinalIdentifier(0)); + + var grouping = new CaseGrouping(new IPredication[] { lowerCase, upperCase }, Context.None); + + var result = grouping.Execute(rs); + Assert.That(result, Has.Count.EqualTo(2)); + Assert.That(result.ElementAt(0).Value.Rows, Has.Count.EqualTo(3)); + Assert.That(result.ElementAt(1).Value.Rows, Has.Count.EqualTo(1)); + } + + [Test] + public void Execute_TwoColumns_ThreeGroups() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "alpha", "1", 10 }, new object[] { "ALPHA", "1", 20 }, new object[] { "beta", "2", 30 }, new object[] { "ALPHA", "2", 40 } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + var lowerCase = new SinglePredication(new TextLowerCase(false), new ColumnOrdinalIdentifier(0)); + var upperCase = new AndCombinationPredication(new List() + { + new SinglePredication(new TextUpperCase(false), new ColumnOrdinalIdentifier(0)), + new SinglePredication(new TextEqual(false, new LiteralScalarResolver("1")), new ColumnOrdinalIdentifier(1)), + }); + + var grouping = new CaseGrouping(new IPredication[] { lowerCase, upperCase }, Context.None); + + var result = grouping.Execute(rs); + Assert.That(result, Has.Count.EqualTo(3)); + Assert.That(result.ElementAt(0).Value.Rows, Has.Count.EqualTo(2)); + Assert.That(result.ElementAt(1).Value.Rows, Has.Count.EqualTo(1)); + Assert.That(result.ElementAt(2).Value.Rows, Has.Count.EqualTo(1)); + } + + [Test] + public void Execute_TwoColumnsWithContext_ThreeGroups() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "alpha", "1", "1" }, new object[] { "ALPHA", "1", "1" }, new object[] { "beta", "2", "2" }, new object[] { "ALPHA", "2", "4" } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + + var context = new Context(null); + var lowerCase = new SinglePredication(new TextLowerCase(false), new ColumnOrdinalIdentifier(0)); + var contextArgs = new ContextScalarResolverArgs(context, new ColumnOrdinalIdentifier(2)); + var upperCase = new AndCombinationPredication(new List() + { + new SinglePredication(new TextUpperCase(false), new ColumnOrdinalIdentifier(0)), + new SinglePredication(new TextEqual(false, new ContextScalarResolver(contextArgs)), new ColumnOrdinalIdentifier(1)), + }); + + var grouping = new CaseGrouping(new IPredication[] { lowerCase, upperCase }, context); + + var result = grouping.Execute(rs); + Assert.That(result, Has.Count.EqualTo(3)); + Assert.That(result.ElementAt(0).Value.Rows, Has.Count.EqualTo(2)); + Assert.That(result.ElementAt(1).Value.Rows, Has.Count.EqualTo(1)); + Assert.That(result.ElementAt(2).Value.Rows, Has.Count.EqualTo(1)); + } + } +} diff --git a/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameColumnGroupingTest.cs similarity index 93% rename from NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs rename to NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameColumnGroupingTest.cs index c48eb9016..34c8656cb 100644 --- a/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameByColumnGroupingTest.cs +++ b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/NameColumnGroupingTest.cs @@ -3,6 +3,7 @@ using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Comparer; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace NBi.Testing.Core.Calculation.Grouping.ColumnBased { - public class NameByColumnGroupingTest + public class NameColumnGroupingTest { [Test] public void Execute_SingleColumn_TwoGroups() @@ -28,7 +29,7 @@ public void Execute_SingleColumn_TwoGroups() new Column() { Identifier = new ColumnNameIdentifier("first"), Role = ColumnRole.Key, Type = ColumnType.Text }, } ); - var grouping = new NameByColumnGrouping(settings); + var grouping = new NameColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(2)); @@ -51,7 +52,7 @@ public void Execute_TwoColumns_ThreeGroups() new Column() { Identifier = new ColumnNameIdentifier("second"), Role = ColumnRole.Key, Type = ColumnType.Text }, } ); - var grouping = new NameByColumnGrouping(settings); + var grouping = new NameColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(3)); @@ -76,7 +77,7 @@ public void Execute_TwoCustomColumns_ThreeGroups() new Column() { Identifier = new ColumnNameIdentifier("second"), Role = ColumnRole.Key, Type = ColumnType.Numeric }, } ); - var grouping = new NameByColumnGrouping(settings); + var grouping = new NameColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(3)); diff --git a/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGroupingTest.cs similarity index 91% rename from NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs rename to NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGroupingTest.cs index 3e18010df..f63d5c37c 100644 --- a/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalByColumnGroupingTest.cs +++ b/NBi.Testing.Core/Calculation/Grouping/ColumnBased/OrdinalColumnGroupingTest.cs @@ -3,6 +3,7 @@ using NBi.Core.ResultSet; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Comparer; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace NBi.Testing.Core.Calculation.Grouping.ColumnBased { - public class OrdinalByColumnGroupingTest + public class OrdinalColumnGroupingTest { [Test] public void Execute_SingleColumn_TwoGroups() @@ -23,7 +24,7 @@ public void Execute_SingleColumn_TwoGroups() var rs = resolver.Execute(); var settings = new SettingsOrdinalResultSet(KeysChoice.First, ValuesChoice.None, NumericAbsoluteTolerance.None); - var grouping = new OrdinalByColumnGrouping(settings); + var grouping = new OrdinalColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(2)); @@ -39,7 +40,7 @@ public void Execute_TwoColumns_ThreeGroups() var rs = resolver.Execute(); var settings = new SettingsOrdinalResultSet(KeysChoice.AllExpectLast, ValuesChoice.None, NumericAbsoluteTolerance.None); - var grouping = new OrdinalByColumnGrouping(settings); + var grouping = new OrdinalColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(3)); @@ -61,7 +62,7 @@ public void Execute_TwoCustomColumns_ThreeGroups() new Column() { Identifier = new ColumnOrdinalIdentifier(1), Role = ColumnRole.Key, Type = ColumnType.Numeric }, } ); - var grouping = new OrdinalByColumnGrouping(settings); + var grouping = new OrdinalColumnGrouping(settings, Context.None); var result = grouping.Execute(rs); Assert.That(result, Has.Count.EqualTo(3)); diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index e23ca2ef3..804ad143f 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -102,14 +102,15 @@ + - - + + diff --git a/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs b/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs index 66c5e16ab..5587fc474 100644 --- a/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs +++ b/NBi.Testing.Core/ResultSet/Filtering/GroupByFilterTest.cs @@ -28,7 +28,7 @@ public void Execute_Top2OneKey_ResultSetReduced() var rs = resolver.Execute(); var settings = new SettingsOrdinalResultSet(KeysChoice.First, ValuesChoice.None, NumericAbsoluteTolerance.None); - var grouping = new OrdinalByColumnGrouping(settings); + var grouping = new OrdinalColumnGrouping(settings, Context.None); var filter = new TopRanking(2, new ColumnOrdinalIdentifier(1), ColumnType.Numeric); From 110762623e3431900ff774bde3bb3333e99f0855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 17 Nov 2019 17:37:54 +0100 Subject: [PATCH 26/57] Add test with genbiL and if-unavailable --- NBi.Testing/Acceptance/GenbiL/ExecutionEqualTo.cs | 1 + .../Acceptance/GenbiL/Resources/ExecutionEqualTo.nbitt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/NBi.Testing/Acceptance/GenbiL/ExecutionEqualTo.cs b/NBi.Testing/Acceptance/GenbiL/ExecutionEqualTo.cs index dd25c428a..316bf4a28 100644 --- a/NBi.Testing/Acceptance/GenbiL/ExecutionEqualTo.cs +++ b/NBi.Testing/Acceptance/GenbiL/ExecutionEqualTo.cs @@ -77,6 +77,7 @@ public void Execute_GenbiL_EqualToIsThere() Assert.That(content, Does.Contain("")); Assert.That(content, Does.Contain("")); Assert.That(content, Does.Contain("")); + Assert.That(content, Does.Contain("")); Assert.That(content, Does.Contain("TC02")); } } diff --git a/NBi.Testing/Acceptance/GenbiL/Resources/ExecutionEqualTo.nbitt b/NBi.Testing/Acceptance/GenbiL/Resources/ExecutionEqualTo.nbitt index 2d9decb6e..521f89c32 100644 --- a/NBi.Testing/Acceptance/GenbiL/Resources/ExecutionEqualTo.nbitt +++ b/NBi.Testing/Acceptance/GenbiL/Resources/ExecutionEqualTo.nbitt @@ -8,6 +8,11 @@ $query$ ]]> + + + + + From 7ef11746426365610f0bdcc952193fb9ee4d7bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Wed, 20 Nov 2019 22:35:45 +0100 Subject: [PATCH 27/57] Update acceptance tests to match with the new syntax 2.0 --- .../Positive/CsvEqualToResultSet.nbits | 52 ++--- .../Resources/Positive/Decoration.nbits | 36 ++-- .../Resources/Positive/Environment.nbits | 30 +-- .../Resources/Positive/MultipleInstance.nbits | 8 +- .../Resources/Positive/QueryAllNoRows.nbits | 158 +++++++------- .../Resources/Positive/QueryEqualToCsv.nbits | 38 ++-- .../Positive/QueryEqualToCsvWithProfile.nbits | 4 +- .../Positive/QueryEqualToQuery - MySQL.nbits | 158 +++++++------- .../Positive/QueryEqualToQuery.nbits | 120 +++++------ .../Positive/QueryEqualToResultSet.nbits | 194 +++++++++--------- .../QueryEqualToResultSetProvider.nbits | 14 +- .../QueryEqualToResultSetWithNull.nbits | 38 ++-- .../Positive/QueryEqualToWithParameter.nbits | 18 +- .../Positive/QuerySubsetOfQuery.nbits | 4 +- .../Positive/QuerySupersetOfQuery.nbits | 4 +- .../Resources/Positive/QueryUniqueRows.nbits | 20 +- .../Positive/QueryWithReference.nbits | 14 +- 17 files changed, 452 insertions(+), 458 deletions(-) diff --git a/NBi.Testing/Acceptance/Resources/Positive/CsvEqualToResultSet.nbits b/NBi.Testing/Acceptance/Resources/Positive/CsvEqualToResultSet.nbits index 21026cf06..a5edf1fbe 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/CsvEqualToResultSet.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/CsvEqualToResultSet.nbits @@ -1,5 +1,5 @@  - + @@ -7,13 +7,13 @@ - + - + - + CY 2005 366 @@ -30,8 +30,8 @@ CY 2008 894 - - + + @@ -39,13 +39,13 @@ - + - + - + CY 2005 366 @@ -62,8 +62,8 @@ CY 2008 894 - - + + @@ -80,13 +80,13 @@ - + - + - + CY 2005 366 @@ -103,8 +103,8 @@ CY 2008 894 - - + + @@ -121,13 +121,13 @@ - + - + - + CY 2005 366 @@ -144,8 +144,8 @@ CY 2008 894 - - + + @@ -162,13 +162,13 @@ - + - + - + CY 2005 366 @@ -185,8 +185,8 @@ CY 2008 894 - - + + diff --git a/NBi.Testing/Acceptance/Resources/Positive/Decoration.nbits b/NBi.Testing/Acceptance/Resources/Positive/Decoration.nbits index 2cc6636dd..e1a60e3af 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/Decoration.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/Decoration.nbits @@ -28,7 +28,7 @@ - + select [Name] @@ -42,12 +42,12 @@ where [Id] in (1,2) - + - + - + Nikola Tesla 1859-07-10 @@ -56,8 +56,8 @@ Leonardo Da Vinci 1456-04-15 - - + + @@ -68,23 +68,23 @@ - + select count(*) from [KeyDates] - + - - + + 3 - - + + @@ -102,11 +102,11 @@ - + OK - + @@ -123,11 +123,11 @@ - + OK - + @@ -144,11 +144,11 @@ - + OK - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/Environment.nbits b/NBi.Testing/Acceptance/Resources/Positive/Environment.nbits index 315610a91..9ee8d9c18 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/Environment.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/Environment.nbits @@ -1,5 +1,5 @@  - + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly @@ -22,54 +22,54 @@ - + @myEnvVar select @var; - + - + - + 2015-01-01 - - + + - + select 2812; - + - + select 2812; - + - + select 2812; - + - + select 2812; - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits index 04d8345d0..6c6156402 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits @@ -10,7 +10,7 @@ - + - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits index 63a99f0c1..bf61caadf 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits @@ -2,10 +2,10 @@ - Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly - Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly @@ -25,7 +25,7 @@ - + select OrderDate @@ -35,7 +35,7 @@ group by OrderDate - + @@ -48,7 +48,7 @@ - + select OrderDate @@ -58,7 +58,7 @@ group by OrderDate - + @@ -71,14 +71,14 @@ - + select [Name], [CountryRegionCode] from [Sales].[SalesTerritory] - + @@ -91,7 +91,7 @@ - + select OrderDate @@ -101,7 +101,7 @@ group by OrderDate - + @@ -114,7 +114,7 @@ - + select OrderDate @@ -124,7 +124,7 @@ group by OrderDate - + @@ -141,13 +141,13 @@ - + select '2015-10-09', 60 union all select '2015-10-10', null union all select '2015-10-11', 75 - + @@ -164,14 +164,14 @@ - + select '2015-10-09', 60 union all select '2015-10-10', null union all select '2015-10-11', 75 union all select '2015-10-12', 110 - + @@ -188,14 +188,14 @@ - + select [Name], [CountryRegionCode] from [Sales].[SalesTerritory] - + @@ -208,7 +208,7 @@ - + select OrderDate @@ -218,7 +218,7 @@ group by OrderDate - + @@ -230,14 +230,14 @@ - + select [Name], [CountryRegionCode] from [Sales].[SalesTerritory] - + @@ -249,11 +249,11 @@ - + select [Name] from [HumanResources].[Department] where Name like 'E%' order by Name - + @@ -266,11 +266,11 @@ - + select [Name] from [HumanResources].[Department] where Name like '%e' order by Name - + @@ -283,11 +283,11 @@ - + select [Name] from [HumanResources].[Department] where Name like '%en%' order by Name - + @@ -300,11 +300,11 @@ - + select [Name] from [HumanResources].[Department] - + @@ -317,11 +317,11 @@ - + select [Name] from [HumanResources].[Department] - + @@ -334,14 +334,14 @@ - + select cast('2015-05-12 14:00:10' as datetime2) union all select cast('2017-04-12 12:10:00' as datetime2) union all select cast('2012-09-12 1:04:00' as datetime2) union all select cast('2013-05-01 00:00:01' as datetime2) - + @@ -353,11 +353,11 @@ - + select 16 union all select 46 union all select 12 union all select 33 - + @@ -369,11 +369,11 @@ - + select 'User' union all select 'Developer' union all select 'Power user' union all select 'User' - + @@ -385,11 +385,11 @@ - + select 'Paris' union all select 'Brussels' union all select 'Toronto' union all select 'Madrid' - + @@ -405,11 +405,11 @@ - + select lower([Name]) from [HumanResources].[Department] - + @@ -422,11 +422,11 @@ - + select upper([Name]) from [HumanResources].[Department] - + @@ -439,11 +439,11 @@ - + select 15 union all select 45 union all select 60 union all select 30 - + @@ -455,14 +455,14 @@ - + select cast('2015-05-12 14:00:00' as datetime2) union all select cast('2017-04-12 12:00:00' as datetime2) union all select cast('2012-09-12 1:00:00' as datetime2) union all select cast('2013-05-01 00:00:00' as datetime2) - + @@ -474,11 +474,11 @@ - + select '15' union all select '45.1' - + @@ -490,12 +490,12 @@ - + select '2015-12-05' union all select '2015-12-25' - + @@ -507,12 +507,12 @@ - + select '25/12/2015' union all select '05/12/2015' - + @@ -524,12 +524,12 @@ - + select 'Paris', 'France' union all select 'Brussels', 'Belgium' - + @@ -545,12 +545,12 @@ - + select year(getdate()) as 'A' union all select year(getdate())-1 - + @@ -580,12 +580,12 @@ - + select year(getdate()) as 'A' union all select year(getdate())-1 - + @@ -598,13 +598,13 @@ - + select year(getdate()) as 'A', 'alpha' as 'B' union all select year(getdate())-1, 'BETA' as 'C' union all select year(getdate())+1, 'GAMMA' as 'C' - + @@ -622,12 +622,12 @@ - + select cast(year(getdate())+1 as varchar(4)) + 'XYZ' as 'A' union all select cast(year(getdate())+1 as varchar(4)) + 'ABC' as 'A' - + @@ -640,15 +640,15 @@ - + select 10 as 'A' ,11 as 'B', 12 as 'C' union all select 5,6,7 union all select 7,8,9 - + @@ -662,15 +662,15 @@ - + select 10 as 'A' ,11 as 'B', 12 as 'C' union all select 5,6,7 union all select 7,8,9 - + @@ -684,15 +684,15 @@ - + select '2019-10-01 06:00:00' as A, '2019-09-30 04:47:00' as 'B', 12 as 'C' union all select '2019-10-01 23:00:00', '2019-10-01 04:42:00' as 'B',7 union all select '2019-10-02 02:00:00', '2019-10-01 04:42:00' as 'B',9 - + @@ -717,15 +717,15 @@ - + select '2019-10-01 06:00:00' as Ref, '07:00:00' as MaxTime, '2019-10-01 06:47:00' as Effective union all select '2019-10-01 22:15:00', '23:00:00', '2019-10-01 22:42:00' union all select '2019-10-02 02:45:00', '03:00:00', '2019-10-02 02:48:00' - + @@ -752,15 +752,15 @@ - + select 'A' as 'Col1' union all select 'B' union all select 'C' - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsv.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsv.nbits index b86260d02..70cdc275d 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsv.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsv.nbits @@ -1,11 +1,11 @@  - + - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -13,19 +13,19 @@ FROM [Adventure Works] - + - + - - + + - + SELECT 'A', 105 @@ -33,24 +33,24 @@ SELECT 'B', NULL - + - + - - + + - + SELECT 'A', 105 - + @@ -73,28 +73,28 @@ - + select 'Key', 'Wrong', /*Should be ignored*/ 'Value' - + - + - + Key Ignore Value - - + + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsvWithProfile.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsvWithProfile.nbits index 7ec24cfe1..7a4c5c926 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsvWithProfile.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToCsvWithProfile.nbits @@ -9,7 +9,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, {[Date].[Calendar Year].[CY 2005]:[Date].[Calendar Year].[CY 2008]} ON 1 @@ -29,7 +29,7 @@ - + SELECT [Key]=1,Val1='2',Val3=NULL,Val3='3' UNION SELECT [Key]=4,Val1=NULL,Val2='3',Val3='' diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery - MySQL.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery - MySQL.nbits index d012fd49d..f3af563be 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery - MySQL.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery - MySQL.nbits @@ -1,5 +1,5 @@  - + Driver={MySQL ODBC 5.3 ANSI Driver};Server=eu-cdbr-azure-west-d.cloudapp.net;User=bdfdabafa6c4ff;password=562d3996 @@ -13,7 +13,7 @@ - + WITH MEMBER [Measures].[Reseller Order Count Divided by 7] @@ -25,10 +25,10 @@ FROM [Adventure Works] - + - + @@ -38,7 +38,7 @@ UNION ALL SELECT 'CY 2008', 894.0/7 UNION ALL SELECT 'CY 2009', NULL - + @@ -46,7 +46,7 @@ - + select [Measures].[Internet Order Count] on 0, @@ -54,10 +54,10 @@ from [Adventure Works] - + - + select [Measures].[Internet Order Count] on 0, @@ -65,73 +65,67 @@ from [Adventure Works] - + Shared - + - + - + - + OK - + Shared - + - + - + - + OK - + Shared - + - + - + - + OK - + @@ -140,17 +134,17 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + select 'OK'; - + - + select 'OK'; - + - + select 'OK'; - + - + select 'OK'; - + - + select '10.2016' union all select '11.2016' - + - + String.Format("{0:00}.{1}", value.Month, value.Year) select cast('2016-10-10' as DateTime) union all select cast('2016-11-22' as DateTime) - + - + select '10.2016', 121 union all select '11.2016',242 - + - + value.Substring(5,2) + "." + value.Substring(0,4) @@ -304,19 +298,19 @@ select '2016.10', 100 union all select '2016.11', 200 - + - + select '10.2016', 121 union all select '11.2016',242 - + - + value.Substring(5,2) + "." + value.Substring(0,4) @@ -326,19 +320,19 @@ select '2016.10', 100 union all select '2016.11', 210 - + - + select '10.2016', cast(121 as decimal(10,3)) union all select '11.2016', cast(242 as decimal(10,3)) - + - + value *1.21 @@ -346,19 +340,19 @@ select '10.2016', 100 union all select '11.2016', 200 - + - + select '10.2016', cast(121 as decimal) union all select '11.2016', cast(242 as decimal) - + - + value *1.21 @@ -366,19 +360,19 @@ select '10.2016', 100 union all select '11.2016', 200 - + - + select '10.2016', '0121.00' union all select '11.2016', '0242.00' - + - + MM.yyyy @@ -388,28 +382,28 @@ select cast('2016-10-01' as DateTime), cast(121 as float) union all select cast('2016-11-01' as DateTime), cast(242 as float) - + - + select 'alpha', '10.250', 'true', '2016-12-10', 'beta' - + - + select 'alpha', cast(10.25 as float) , cast(1 as bit), cast('2016-12-10' as DateTime), 'beta' - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery.nbits index 18d3edea7..8773248bd 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToQuery.nbits @@ -17,12 +17,12 @@ - + SELECT @cyYear, 366 ~CY {@TwoThousandAndFive:yyyy} - + @@ -37,7 +37,7 @@ - + WITH MEMBER [Measures].[Reseller Order Count Divided by 7] @@ -49,7 +49,7 @@ FROM [Adventure Works] - + @@ -70,7 +70,7 @@ - + select [Measures].[Internet Order Count] on 0, @@ -78,7 +78,7 @@ from [Adventure Works] - + @@ -96,13 +96,13 @@ Shared - + - + @@ -118,13 +118,13 @@ Shared - + - + @@ -140,13 +140,13 @@ Shared - + - + @@ -164,14 +164,14 @@ - + - + @@ -187,14 +187,14 @@ - + - + @@ -210,14 +210,14 @@ - + - + @@ -233,14 +233,14 @@ - + - + @@ -258,11 +258,11 @@ - + select 'OK'; - + @@ -274,11 +274,11 @@ - + select 'OK'; - + @@ -292,11 +292,11 @@ - + select '10.2016' union all select '11.2016' - + @@ -311,11 +311,11 @@ - + select '10.2016', 121 union all select '11.2016',242 - + @@ -333,11 +333,11 @@ - + select '10.2016', 121 union all select '11.2016',242 - + @@ -355,11 +355,11 @@ - + select '10.2016', cast(121 as decimal(10,3)) union all select '11.2016', cast(242 as decimal(10,3)) - + @@ -375,11 +375,11 @@ - + select '10.2016', cast(121 as float) union all select '11.2016', cast(242 as float) - + @@ -395,11 +395,11 @@ - + select 'alpha', null union all select 'beta', null - + @@ -417,11 +417,11 @@ - + select 'alpha', LEN('alpha') union all select 'beta', LEN('beta') - + @@ -438,11 +438,11 @@ - + select 'alpha', '10.250', 'true', '2016-12-10', 'beta' - + @@ -457,11 +457,11 @@ - + select 'alpha' as 'A', '10.250' as 'B', 'true' as 'C', '2016-12-10' as 'D', 'beta' as 'E' - + @@ -478,9 +478,9 @@ - + select 'Alpha' as 'Key', '100' as 'Value1', 100.0 as Value2 union all select 'Beta' as 'Key', '120', 100.00 as Value2 - + @@ -492,9 +492,9 @@ - + select 'Alpha' as 'Key', '100' as 'Value' union all select 'Beta' as 'Key', '120' - + @@ -508,9 +508,9 @@ - + select 'Alpha' as 'KeyField', '2016-12-10' as 'Value' union all select 'Beta' as 'KeyField', '2016-02-02' - + @@ -523,9 +523,9 @@ - + select 'Alpha' as 'KeyField', '2016-12-10' as 'Value' union all select 'Beta' as 'KeyField', '2016-02-02' - + @@ -538,9 +538,9 @@ - + select '10' as 'KeyField', '2016-12-10' as 'Value' union all select '12.0' as 'KeyField', '2016-02-02' - + @@ -562,13 +562,13 @@ - + select 1 as [key], 'Saskatchewan' as [value] union all select 2, 'Michigan' union all select 3, 'Chihuahua' - + @@ -582,13 +582,13 @@ - + select 1 as [key], 'Saskatcheone' as [value] union all select 2, 'Michigane' union all select 3, 'Chihuawa' - + @@ -602,13 +602,13 @@ - + select 1 as [key], 'Saskatcheone' as [value] union all select 2, 'Michigane' union all select 3, 'Chihuawa' - + @@ -623,13 +623,13 @@ - + select 1 as [key], 'Toronto' as [value] union all select 2, 'Ottawa' union all select 3, 'Vancouver' - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSet.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSet.nbits index 1870d5a67..7391637c7 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSet.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSet.nbits @@ -1,5 +1,5 @@  - + Provider=MSOLAP.4;Data Source=(local)\SQL2017;Initial Catalog='Adventure Works DW 2012';localeidentifier=1049 @@ -13,7 +13,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -21,11 +21,11 @@ FROM [Adventure Works] - + - - + + CY 2005 366 @@ -42,8 +42,8 @@ CY 2008 894 - - + + @@ -51,7 +51,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -59,12 +59,12 @@ FROM [Adventure Works] - + - + - + CY 2005 350 @@ -81,8 +81,8 @@ CY 2008 900 - - + + @@ -90,7 +90,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -98,12 +98,12 @@ FROM [Adventure Works] - + - + - + CY 2005 300 @@ -120,8 +120,8 @@ CY 2008 800 - - + + @@ -129,7 +129,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -137,12 +137,12 @@ FROM [Adventure Works] - + - + - + CY 2005 [-INF;372[ @@ -159,8 +159,8 @@ CY 2008 894 - - + + @@ -168,7 +168,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -176,12 +176,12 @@ FROM [Adventure Works] - + - + - + CY 2005 360 @@ -198,13 +198,13 @@ CY 2008 (absolutely-positive) - - + + - + SELECT 'Id-1' @@ -214,12 +214,12 @@ 'Id-2' , cast('2013-11-22 23:00:00' as datetime) - + - + - + Id-1 2013-11-21 23:00:00 @@ -228,8 +228,8 @@ Id-2 2013-11-23 - - + + @@ -237,7 +237,7 @@ - + @@ -246,11 +246,11 @@ VALUES('Product Subcategory'[Product Subcategory Name]), 'Product Category'[Product Category Name] = "Bikes") - + - - + + Mountain Bikes @@ -260,8 +260,8 @@ Touring Bikes - - + + @@ -269,7 +269,7 @@ - + @@ -279,22 +279,22 @@ "MaxOrderDate", max('Internet Sales'[OrderDateKey]) ) ) - + - - + + 20050701 20080731 - - + + - + @@ -305,11 +305,11 @@ where [Group]='Europe' - + - - + + France FR @@ -322,13 +322,13 @@ United Kingdom GB - - + + - + @@ -340,11 +340,11 @@ [Group]=@Area Europe - + - - + + France FR @@ -357,13 +357,13 @@ United Kingdom GB - - + + - + @@ -374,11 +374,11 @@ [Group]='Europe' from [Sales].[SalesTerritory] - + - - + + France FR @@ -391,25 +391,25 @@ United Kingdom GB - - + + - + select cast ('2015-12-16' as date), 412.25 union all select cast ('2015-12-17' as date), 725.0 - + - + - + 2015-12-16 412.250 @@ -418,13 +418,13 @@ 2015-12-17 725 - - + + - + @@ -442,11 +442,11 @@ , 'Smiljan' , 'Croatia' - + - - + + Nikola Tesla Electrical engineering @@ -461,13 +461,13 @@ Toronto Canada - - + + - + @@ -481,11 +481,11 @@ , '−211' , '−195.77' - + - - + + Water -0.4 @@ -496,13 +496,13 @@ -210 -195.79 - - + + - + @@ -511,20 +511,20 @@ , 101.8 , -0.4 - + - + - + Water 100 -1 - - + + @@ -532,7 +532,7 @@ - + select [Measures].[Internet Sales Amount] on 0 @@ -540,11 +540,11 @@ from [Adventure Works] - + - - + + Europe 8930042 @@ -561,8 +561,8 @@ NA (any) - - + + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetProvider.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetProvider.nbits index 1a62320fd..4ba68b3dc 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetProvider.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetProvider.nbits @@ -1,11 +1,11 @@  - + - + - + - - + + CY 2005 366 @@ -37,8 +37,8 @@ CY 2008 894 - - + + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetWithNull.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetWithNull.nbits index 4fbd1af1c..30d344ed6 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetWithNull.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToResultSetWithNull.nbits @@ -1,16 +1,16 @@  - + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly - + - + select '001', 100 @@ -101,12 +101,12 @@ select '', 300 - + - + 001 100 @@ -119,7 +119,7 @@ (empty) 300 - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToWithParameter.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToWithParameter.nbits index 7e76e6143..25ab4b060 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToWithParameter.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryEqualToWithParameter.nbits @@ -1,5 +1,5 @@  - + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly @@ -23,32 +23,32 @@ - + 1 - + - + @CurrencyCodeVariable - + - - + + CAD Canadian Dollar - - + + \ No newline at end of file diff --git a/NBi.Testing/Acceptance/Resources/Positive/QuerySubsetOfQuery.nbits b/NBi.Testing/Acceptance/Resources/Positive/QuerySubsetOfQuery.nbits index 97d49c7fc..725c6b3b6 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QuerySubsetOfQuery.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QuerySubsetOfQuery.nbits @@ -10,12 +10,12 @@ - + SELECT 'CY 2006', 1015.0 UNION ALL SELECT 'CY 2007', 1521.0 - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QuerySupersetOfQuery.nbits b/NBi.Testing/Acceptance/Resources/Positive/QuerySupersetOfQuery.nbits index 9c75b841d..42324e6a4 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QuerySupersetOfQuery.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QuerySupersetOfQuery.nbits @@ -10,7 +10,7 @@ - + SELECT 'CY 2005', 366.0 UNION ALL SELECT 'CY 2006', 1015.0 @@ -18,7 +18,7 @@ UNION ALL SELECT 'CY 2008', 894.0 UNION ALL SELECT 'CY 2009', NULL - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryUniqueRows.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryUniqueRows.nbits index 69b79a2d0..379bdcbb3 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryUniqueRows.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryUniqueRows.nbits @@ -7,12 +7,12 @@ - + select 'alpha' as 'A', 100 as 'B' union all select 'beta', 100 - + @@ -20,13 +20,13 @@ - + select 'alpha' as 'A', 100 as 'B', 110 as 'C' union all select 'beta', 100, 120 union all select 'gamma', 110, 105 - + @@ -34,13 +34,13 @@ - + select 'alpha' as 'A', 100 as 'B', 110 as 'C' union all select 'alpha', 105, 110 union all select 'gamma', 110, 105 - + @@ -52,13 +52,13 @@ - + select 'alpha' as 'A', 100 as 'B', 110 as 'C' union all select 'alpha', 105, 110 union all select 'gamma', 110, 105 - + @@ -70,12 +70,12 @@ - + select 'alpha' as 'A', '100' as 'B' union all select 'alpha', '102.0' - + diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryWithReference.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryWithReference.nbits index 12798a983..88b85cdcd 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryWithReference.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryWithReference.nbits @@ -1,5 +1,5 @@  - + Provider=MSOLAP.4;Data Source=(local)\SQL2017;Initial Catalog='Adventure Works DW 2012';localeidentifier=1049 @@ -10,7 +10,7 @@ - + SELECT [Measures].[Reseller Order Count] ON 0, @@ -18,11 +18,11 @@ FROM [Adventure Works] - + - - + + CY 2005 366 @@ -39,8 +39,8 @@ CY 2008 894 - - + + From ecb907e0b6e76d9355ff3701ecc59cf228e8c10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 18 Nov 2019 21:42:27 +0100 Subject: [PATCH 28/57] [WIP] Serialization and Mapping --- .../Grouping/CaseBased/CaseGroupByArgs.cs | 3 + .../Calculation/Grouping/GroupByFactory.cs | 1 + .../GroupByFactory.cs~Stashed changes | 81 +++++++++++++++++++ .../Calculation/Grouping/NoneGroupByArgs.cs | 11 +++ .../Calculation/Predicate/PredicateArgs.cs | 12 +-- .../Predication/PredicationFactory.cs | 2 +- NBi.Core/Calculation/Ranking/RankingArgs.cs | 23 ++++++ .../Calculation/Ranking/RankingFactory.cs | 8 +- NBi.Core/NBi.Core.csproj | 5 ++ NBi.Core/ResultSet/Filtering/GroupByFilter.cs | 2 +- .../ResultSet/Filtering/IFilteringArgs.cs | 11 +++ .../ResultSet/Filtering/PredicationArgs.cs | 20 +++++ .../ResultSet/Filtering/RankingGroupByArgs.cs | 18 +++++ .../Filtering/ResultSetFilterFactory.cs | 32 ++++---- .../Builder/Helper/ResultSetSystemHelper.cs | 43 +++++++++- NBi.NUnit/NBi.NUnit.csproj | 2 +- NBi.Testing.Xml/Constraints/AllRowsXmlTest.cs | 40 ++++----- .../Items/Calculation/PredicateXmlTest.cs | 4 +- .../Items/Calculation/RankingXmlTest.cs | 36 +++++++++ .../Resources/RankingXmlTestSuite.xml | 40 +++++++++ .../Positive/ResultSetConstraint.nbits | 70 ++++++++++++++-- .../Builder/ResultSetAllRowsBuilderTest.cs | 10 +-- .../Builder/ResultSetRowCountBuilderTest.cs | 4 +- .../Builder/ResultSetSingleRowBuilderTest.cs | 10 +-- .../Builder/ResultSetSomeRowsBuilderTest.cs | 10 +-- NBi.Xml/Constraints/NoRowsXml.cs | 4 +- NBi.Xml/Items/AbstractPredicationXml.cs | 11 +++ ...ateXml.cs => CombinationPredicationXml.cs} | 4 +- NBi.Xml/Items/Calculation/FilterXml.cs | 4 +- NBi.Xml/Items/Calculation/Grouping/CaseXml.cs | 16 ++++ .../Items/Calculation/Grouping/GroupByxml.cs | 3 + ...dicationXml.cs => SinglePredicationXml.cs} | 4 +- NBi.Xml/NBi.Xml.csproj | 6 +- NBi.Xml/Schema/BaseType.xsd | 17 +++- .../SerializationOption/ReadOnlyAttributes.cs | 4 +- 35 files changed, 474 insertions(+), 97 deletions(-) create mode 100644 NBi.Core/Calculation/Grouping/GroupByFactory.cs~Stashed changes create mode 100644 NBi.Core/Calculation/Grouping/NoneGroupByArgs.cs create mode 100644 NBi.Core/Calculation/Ranking/RankingArgs.cs create mode 100644 NBi.Core/ResultSet/Filtering/IFilteringArgs.cs create mode 100644 NBi.Core/ResultSet/Filtering/PredicationArgs.cs create mode 100644 NBi.Core/ResultSet/Filtering/RankingGroupByArgs.cs create mode 100644 NBi.Xml/Items/AbstractPredicationXml.cs rename NBi.Xml/Items/Calculation/{CombinationPredicateXml.cs => CombinationPredicationXml.cs} (81%) create mode 100644 NBi.Xml/Items/Calculation/Grouping/CaseXml.cs rename NBi.Xml/Items/Calculation/{PredicationXml.cs => SinglePredicationXml.cs} (96%) diff --git a/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs b/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs index be6c06ff0..7adbac851 100644 --- a/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs +++ b/NBi.Core/Calculation/Grouping/CaseBased/CaseGroupByArgs.cs @@ -12,5 +12,8 @@ public class CaseGroupByArgs : IGroupByArgs { public IEnumerable Cases { get; set; } public Context Context { get; set; } + + public CaseGroupByArgs(IEnumerable cases, Context context) + => (Cases, Context) = (cases, context); } } diff --git a/NBi.Core/Calculation/Grouping/GroupByFactory.cs b/NBi.Core/Calculation/Grouping/GroupByFactory.cs index d167f2ab9..5cc5d8cab 100644 --- a/NBi.Core/Calculation/Grouping/GroupByFactory.cs +++ b/NBi.Core/Calculation/Grouping/GroupByFactory.cs @@ -23,6 +23,7 @@ public IGroupBy Instantiate(IGroupByArgs args) { switch (args) { + case NoneGroupByArgs x: return None(); case ColumnGroupByArgs x: return Instantiate(x.Columns, x.Context); case CaseGroupByArgs x: return new CaseGrouping(x.Cases, x.Context); default: throw new ArgumentOutOfRangeException(); diff --git a/NBi.Core/Calculation/Grouping/GroupByFactory.cs~Stashed changes b/NBi.Core/Calculation/Grouping/GroupByFactory.cs~Stashed changes new file mode 100644 index 000000000..02fa051fd --- /dev/null +++ b/NBi.Core/Calculation/Grouping/GroupByFactory.cs~Stashed changes @@ -0,0 +1,81 @@ +using NBi.Core.Calculation.Grouping.CaseBased; +using NBi.Core.Calculation.Grouping.ColumnBased; +using NBi.Core.Calculation.Predication; +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Equivalence; +using NBi.Core.Scalar.Comparer; +using NBi.Core.Transformation; +using NBi.Core.Variable; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static NBi.Core.ResultSet.SettingsOrdinalResultSet; + +namespace NBi.Core.Calculation.Grouping +{ + public class GroupByFactory + { + public static IGroupBy None() => new NoneGrouping(); + + public IGroupBy Instantiate(IGroupByArgs args) + { + switch (args) + { + case NoneGroupByArgs _: return None(); + case ColumnGroupByArgs x: return Instantiate(x.Columns, x.Context); + case CaseGroupByArgs x: return new CaseGrouping(x.Cases, x.Context); + default: throw new ArgumentOutOfRangeException(); + } + } + + private IGroupBy Instantiate(IEnumerable columns, Context context) + { + if ((columns?.Count() ?? 0) == 0) + return new NoneGrouping(); + + var definitions = new List(); + foreach (var column in columns) + { + var definition = new ColumnDefinition() + { + Identifier = column.Identifier, + Type = column.Type + }; + definitions.Add(definition); + } + + var builder = new SettingsEquivalerBuilder(); + builder.Setup(KeysChoice.None, ValuesChoice.None); + builder.Setup(definitions); + builder.Build(); + + var settings = builder.GetSettings(); + if (settings is SettingsOrdinalResultSet) + return new OrdinalColumnGrouping(settings as SettingsOrdinalResultSet, context); + + else if (settings is SettingsNameResultSet) + return new NameColumnGrouping(settings as SettingsNameResultSet, context); + + throw new ArgumentOutOfRangeException(nameof(settings)); + } + + private class ColumnDefinition : IColumnDefinition + { + public IColumnIdentifier Identifier { get; set; } + public ColumnRole Role { get => ColumnRole.Key; set => throw new NotImplementedException(); } + public ColumnType Type { get; set; } + + + public string Tolerance { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public bool IsToleranceSpecified => false; + + public Rounding.RoundingStyle RoundingStyle { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string RoundingStep { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public ITransformationInfo Transformation => throw new NotImplementedException(); + } + } +} diff --git a/NBi.Core/Calculation/Grouping/NoneGroupByArgs.cs b/NBi.Core/Calculation/Grouping/NoneGroupByArgs.cs new file mode 100644 index 000000000..969e840c9 --- /dev/null +++ b/NBi.Core/Calculation/Grouping/NoneGroupByArgs.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Grouping +{ + public class NoneGroupByArgs : IGroupByArgs + { } +} diff --git a/NBi.Core/Calculation/Predicate/PredicateArgs.cs b/NBi.Core/Calculation/Predicate/PredicateArgs.cs index 6d3f68e3b..9dd3cb91a 100644 --- a/NBi.Core/Calculation/Predicate/PredicateArgs.cs +++ b/NBi.Core/Calculation/Predicate/PredicateArgs.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Filtering; using System; using System.Collections.Generic; using System.Linq; @@ -33,15 +34,4 @@ public class CultureSensitivePredicateArgs : PredicateArgs { public virtual string Culture { get; set; } } - - public class PredicationArgs - { - public PredicationArgs() { } - - public PredicationArgs(IColumnIdentifier identifier, PredicateArgs predicate) - => (Identifier, Predicate) = (identifier, predicate); - - public virtual PredicateArgs Predicate { get; set; } - public virtual IColumnIdentifier Identifier { get; set; } - } } diff --git a/NBi.Core/Calculation/Predication/PredicationFactory.cs b/NBi.Core/Calculation/Predication/PredicationFactory.cs index 6b2a94d76..23a2ef8f5 100644 --- a/NBi.Core/Calculation/Predication/PredicationFactory.cs +++ b/NBi.Core/Calculation/Predication/PredicationFactory.cs @@ -9,7 +9,7 @@ namespace NBi.Core.Calculation.Predication { - class PredicationFactory + public class PredicationFactory { public IPredication Instantiate(IPredicate predicate, IColumnIdentifier operand) => new SinglePredication(predicate, operand); diff --git a/NBi.Core/Calculation/Ranking/RankingArgs.cs b/NBi.Core/Calculation/Ranking/RankingArgs.cs new file mode 100644 index 000000000..f70a9c474 --- /dev/null +++ b/NBi.Core/Calculation/Ranking/RankingArgs.cs @@ -0,0 +1,23 @@ +using NBi.Core.ResultSet; +using NBi.Core.ResultSet.Filtering; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Calculation.Ranking +{ + public class RankingArgs : IRankingInfo + { + public RankingOption Option { get; } + + public int Count { get; } + + public IColumnIdentifier Operand { get; set; } + public ColumnType Type { get; set; } + + public RankingArgs(RankingOption option, int count, IColumnIdentifier operand, ColumnType type) + => (Option, Count, Operand, Type) = (option, count, operand, type); + } +} diff --git a/NBi.Core/Calculation/Ranking/RankingFactory.cs b/NBi.Core/Calculation/Ranking/RankingFactory.cs index 6ae1e7f67..634f50936 100644 --- a/NBi.Core/Calculation/Ranking/RankingFactory.cs +++ b/NBi.Core/Calculation/Ranking/RankingFactory.cs @@ -8,14 +8,14 @@ namespace NBi.Core.Calculation.Ranking { public class RankingFactory { - public AbstractRanking Instantiate(IRankingInfo info) + public AbstractRanking Instantiate(RankingArgs args) { - switch (info.Option) + switch (args.Option) { case RankingOption.Top: - return new TopRanking(info.Count, info.Operand, info.Type); + return new TopRanking(args.Count, args.Operand, args.Type); case RankingOption.Bottom: - return new BottomRanking(info.Count, info.Operand, info.Type); + return new BottomRanking(args.Count, args.Operand, args.Type); default: throw new ArgumentOutOfRangeException(); } diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 70a68c095..595d5c3ad 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -148,6 +148,9 @@ + + + @@ -163,8 +166,10 @@ + + diff --git a/NBi.Core/ResultSet/Filtering/GroupByFilter.cs b/NBi.Core/ResultSet/Filtering/GroupByFilter.cs index aa8135cc6..ca3b4fd6c 100644 --- a/NBi.Core/ResultSet/Filtering/GroupByFilter.cs +++ b/NBi.Core/ResultSet/Filtering/GroupByFilter.cs @@ -36,6 +36,6 @@ public ResultSet AntiApply(ResultSet rs) => throw new NotImplementedException(); public string Describe() - => throw new NotImplementedException(); + => $"{Filter.Describe()} after grouping by {GroupBy.ToString()}"; } } diff --git a/NBi.Core/ResultSet/Filtering/IFilteringArgs.cs b/NBi.Core/ResultSet/Filtering/IFilteringArgs.cs new file mode 100644 index 000000000..51f41b2da --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/IFilteringArgs.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + public interface IFilteringArgs + { } +} diff --git a/NBi.Core/ResultSet/Filtering/PredicationArgs.cs b/NBi.Core/ResultSet/Filtering/PredicationArgs.cs new file mode 100644 index 000000000..cafff4ccd --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/PredicationArgs.cs @@ -0,0 +1,20 @@ +using NBi.Core.Calculation.Predicate; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + public class PredicationArgs : IFilteringArgs + { + public PredicationArgs() { } + + public PredicationArgs(IColumnIdentifier identifier, PredicateArgs predicate) + => (Identifier, Predicate) = (identifier, predicate); + + public virtual PredicateArgs Predicate { get; set; } + public virtual IColumnIdentifier Identifier { get; set; } + } +} diff --git a/NBi.Core/ResultSet/Filtering/RankingGroupByArgs.cs b/NBi.Core/ResultSet/Filtering/RankingGroupByArgs.cs new file mode 100644 index 000000000..c1d06b387 --- /dev/null +++ b/NBi.Core/ResultSet/Filtering/RankingGroupByArgs.cs @@ -0,0 +1,18 @@ +using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Ranking; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.ResultSet.Filtering +{ + public class RankingGroupByArgs : RankingArgs, IFilteringArgs + { + public IGroupBy GroupBy { get; } + + public RankingGroupByArgs(IGroupBy groupBy, RankingOption option, int count, IColumnIdentifier operand, ColumnType type) + : base (option, count, operand, type) => GroupBy = groupBy; + } +} diff --git a/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs index 8059bed94..4b719a0e6 100644 --- a/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs +++ b/NBi.Core/ResultSet/Filtering/ResultSetFilterFactory.cs @@ -1,5 +1,6 @@ using NBi.Core.Calculation; using NBi.Core.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.CaseBased; using NBi.Core.Calculation.Grouping.ColumnBased; using NBi.Core.Calculation.Predicate; using NBi.Core.Calculation.Predicate.Combination; @@ -25,7 +26,17 @@ public class ResultSetFilterFactory public ResultSetFilterFactory(ServiceLocator serviceLocator) => (ServiceLocator) = (serviceLocator); - public IResultSetFilter Instantiate(PredicationArgs predicationArgs, Context context) + public IResultSetFilter Instantiate(IFilteringArgs filteringArgs, Context context) + { + switch (filteringArgs) + { + case PredicationArgs args: return InstantiatePredication(args, context); + case RankingGroupByArgs args: return InstantiateRanking(args, context); + default: throw new ArgumentOutOfRangeException(); + } + } + + private IResultSetFilter InstantiatePredication(PredicationArgs predicationArgs, Context context) { if (predicationArgs.Identifier == null) throw new ArgumentException("You must specify an operand for a predication. The operand is the column or alias or expression on which the predicate will be evaluated."); @@ -40,6 +51,12 @@ public IResultSetFilter Instantiate(PredicationArgs predicationArgs, Context con return filter; } + private IResultSetFilter InstantiateRanking(RankingGroupByArgs args, Context context) + { + var ranking = new RankingFactory().Instantiate(args); + return new GroupByFilter(ranking, args.GroupBy); + } + public IResultSetFilter Instantiate(CombinationOperator combinationOperator, IEnumerable predicationArgs, Context context) { var predications = new List(); @@ -61,18 +78,5 @@ public IResultSetFilter Instantiate(CombinationOperator combinationOperator, IEn var filter = new PredicationFilter(predication, context); return filter; } - - - public IResultSetFilter Instantiate(IRankingInfo rankingInfo, IEnumerable columns) - { - var groupingFactory = new GroupByFactory(); - var groupingArgs = new ColumnGroupByArgs(columns, Context.None); - var grouping = groupingFactory.Instantiate(groupingArgs); - - var rankingFactory = new RankingFactory(); - var ranking = rankingFactory.Instantiate(rankingInfo); - - return new GroupByFilter(ranking, grouping); - } } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs index 4b75b1250..ecb3fd00b 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs @@ -35,6 +35,11 @@ using NBi.Core.ResultSet.Alteration.Lookup.Strategies.Missing; using NBi.Core.ResultSet.Alteration.Renaming.Strategies.Missing; using NBi.Core.ResultSet.Filtering; +using NBi.Core.Calculation.Grouping; +using NBi.Xml.Items.Calculation.Grouping; +using NBi.Core.Calculation.Grouping.ColumnBased; +using NBi.Core.Calculation.Grouping.CaseBased; +using NBi.Core.Calculation.Predication; namespace NBi.NUnit.Builder.Helper { @@ -125,11 +130,41 @@ private Alter InstantiateFilter(FilterXml filterXml) } else { - return factory.Instantiate( - filterXml.Ranking, - filterXml.Ranking?.GroupBy?.Columns - ).Apply; + var groupByArgs = BuildGroupByArgs(filterXml.Ranking.GroupBy, context); + var groupByFactory = new GroupByFactory(); + var groupBy = groupByFactory.Instantiate(groupByArgs); + + var rankingGroupByArgs = new RankingGroupByArgs(groupBy, filterXml.Ranking.Option, filterXml.Ranking.Count, filterXml.Ranking.Operand, filterXml.Ranking.Type); + return factory.Instantiate(rankingGroupByArgs, context).Apply; + } + } + + private IGroupByArgs BuildGroupByArgs(GroupByXml xml, Context context) + { + if (xml == null) + return new NoneGroupByArgs(); + if ((xml?.Columns?.Count ?? 0) > 0) + return new ColumnGroupByArgs(xml.Columns, context); + if ((xml?.Cases?.Count ?? 0) > 0) + { + var builder = new PredicateArgsBuilder(ServiceLocator, context); + var predications = new List(); + foreach (var caseXml in xml.Cases) + { + if (caseXml.Predication is SinglePredicationXml) + { + var predicationXml = (caseXml.Predication) as SinglePredicationXml; + var args = builder.Execute(predicationXml.ColumnType, predicationXml.Predicate); + var predicate = new PredicateFactory().Instantiate(args); + var predicationFactory = new PredicationFactory(); + predications.Add(predicationFactory.Instantiate(predicate, predicationXml.Operand)); + + } + } + + return new CaseGroupByArgs(predications, context); } + throw new ArgumentOutOfRangeException(); } private Alter InstantiateConvert(ConvertXml convertXml) diff --git a/NBi.NUnit/NBi.NUnit.csproj b/NBi.NUnit/NBi.NUnit.csproj index ee4cb991e..961256e54 100644 --- a/NBi.NUnit/NBi.NUnit.csproj +++ b/NBi.NUnit/NBi.NUnit.csproj @@ -189,7 +189,7 @@ NBi.Framework - {3A9822B3-CCE4-441B-9C3E-D52817A994CA} + {3a9822b3-cce4-441b-9c3e-d52817a994ca} NBi.Xml diff --git a/NBi.Testing.Xml/Constraints/AllRowsXmlTest.cs b/NBi.Testing.Xml/Constraints/AllRowsXmlTest.cs index 2f84924d7..f32ebc403 100644 --- a/NBi.Testing.Xml/Constraints/AllRowsXmlTest.cs +++ b/NBi.Testing.Xml/Constraints/AllRowsXmlTest.cs @@ -305,7 +305,7 @@ public void Serialize_AllRowsXml_OnlyAliasNoVariable() new AliasXml() {Column = 1, Name="Col1"}, new AliasXml() {Column = 0, Name="Col2"} }, - Predication = new PredicationXml() + Predication = new SinglePredicationXml() }; #pragma warning restore 0618 @@ -328,7 +328,7 @@ public void Serialize_AllRowsXml_AnyOfXml() { var allRowsXml = new AllRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new AnyOfXml() { @@ -423,7 +423,7 @@ public void Serialize_ExecutionAndAliasesXml_AliasesBeforeExecution() } }, - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnNameIdentifier("calculate"), ColumnType = ColumnType.Numeric, @@ -464,7 +464,7 @@ public void Serialize_UnspecifiedExpression_NoScript() } }, - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnNameIdentifier("calculate"), ColumnType = ColumnType.Numeric, @@ -503,7 +503,7 @@ public void Serialize_NCalcExpression_NoScript() } }, - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnNameIdentifier("calculate"), ColumnType = ColumnType.Numeric, @@ -542,7 +542,7 @@ public void Serialize_NativeExpression_ScriptIsAvailable() } }, - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnNameIdentifier("calculate"), ColumnType = ColumnType.Numeric, @@ -571,7 +571,7 @@ public void Serialize_NativeExpression_ScriptIsAvailable() [Test] public void Serialize_MatchesRegex_WithCDATA() { - var root = new PredicationXml() + var root = new SinglePredicationXml() { Predicate = new MatchesRegexXml { Reference = "<|>|&" } }; @@ -591,12 +591,12 @@ public void Serialize_MatchesRegex_WithCDATA() [Test] public void Deserialize_MatchesRegex_WithCDATA() { - var xml = "|&]]>"; + var xml = "|&]]>"; var manager = new XmlManager(); var overrides = new ReadOnlyAttributes(); overrides.Build(); - var objectData = manager.XmlDeserializeTo(xml, overrides); - Assert.That(objectData, Is.TypeOf()); + var objectData = manager.XmlDeserializeTo(xml, overrides); + Assert.That(objectData, Is.TypeOf()); Assert.That(objectData, Is.Not.Null); Assert.That(objectData.Predicate, Is.TypeOf()); var predicate = objectData.Predicate as MatchesRegexXml; @@ -607,12 +607,12 @@ public void Deserialize_MatchesRegex_WithCDATA() [Test] public void Deserialize_MatchesRegex_WithoutCDATA() { - var xml = "<|>|&"; + var xml = "<|>|&"; var manager = new XmlManager(); var overrides = new ReadOnlyAttributes(); overrides.Build(); - var objectData = manager.XmlDeserializeTo(xml, overrides); - Assert.That(objectData, Is.TypeOf()); + var objectData = manager.XmlDeserializeTo(xml, overrides); + Assert.That(objectData, Is.TypeOf()); Assert.That(objectData, Is.Not.Null); Assert.That(objectData.Predicate, Is.TypeOf()); var predicate = objectData.Predicate as MatchesRegexXml; @@ -623,7 +623,7 @@ public void Deserialize_MatchesRegex_WithoutCDATA() [Test] public void Serialize_Equal_WithoutCDATAButWithZero() { - var root = new PredicationXml() + var root = new SinglePredicationXml() { Predicate = new EqualXml() { Reference = "0" } }; @@ -641,12 +641,12 @@ public void Serialize_Equal_WithoutCDATAButWithZero() [Test] public void Deserialize_Equal_WithCDATA() { - var xml = "|&]]>"; + var xml = "|&]]>"; var manager = new XmlManager(); var overrides = new ReadOnlyAttributes(); overrides.Build(); - var objectData = manager.XmlDeserializeTo(xml, overrides); - Assert.That(objectData, Is.TypeOf()); + var objectData = manager.XmlDeserializeTo(xml, overrides); + Assert.That(objectData, Is.TypeOf()); Assert.That(objectData, Is.Not.Null); Assert.That(objectData.Predicate, Is.TypeOf()); var predicate = objectData.Predicate as EqualXml; @@ -657,12 +657,12 @@ public void Deserialize_Equal_WithCDATA() [Test] public void Deserialize_Equal_WithoutCDATA() { - var xml = "<|>|&"; + var xml = "<|>|&"; var manager = new XmlManager(); var overrides = new ReadOnlyAttributes(); overrides.Build(); - var objectData = manager.XmlDeserializeTo(xml, overrides); - Assert.That(objectData, Is.TypeOf()); + var objectData = manager.XmlDeserializeTo(xml, overrides); + Assert.That(objectData, Is.TypeOf()); Assert.That(objectData, Is.Not.Null); Assert.That(objectData.Predicate, Is.TypeOf()); var predicate = objectData.Predicate as EqualXml; diff --git a/NBi.Testing.Xml/Items/Calculation/PredicateXmlTest.cs b/NBi.Testing.Xml/Items/Calculation/PredicateXmlTest.cs index 6e73767cd..1eae4339a 100644 --- a/NBi.Testing.Xml/Items/Calculation/PredicateXmlTest.cs +++ b/NBi.Testing.Xml/Items/Calculation/PredicateXmlTest.cs @@ -66,7 +66,7 @@ public void Serialize_PredicateXml_OnlyOperandNoName() { var allRowsXml = new AllRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnOrdinalIdentifier(1), Predicate = new FalseXml() @@ -92,7 +92,7 @@ public void Serialize_ModuloXml_AllPredicateInfoCorrectlySerialized() { var allRowsXml = new AllRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Operand = new ColumnOrdinalIdentifier(1), Predicate = new ModuloXml() { SecondOperand = "10", Reference = "5" } diff --git a/NBi.Testing.Xml/Items/Calculation/RankingXmlTest.cs b/NBi.Testing.Xml/Items/Calculation/RankingXmlTest.cs index bbff15ede..368d08e26 100644 --- a/NBi.Testing.Xml/Items/Calculation/RankingXmlTest.cs +++ b/NBi.Testing.Xml/Items/Calculation/RankingXmlTest.cs @@ -198,5 +198,41 @@ public void Serialize_WithGroupBy_RankingXml() Assert.That(content, Does.Contain("bar")); Assert.That(content, Does.Not.Contain("text")); } + + [Test] + public void Deserialize_RankingWithCases_CaseGrouping() + { + int testNr = 2; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var alterations = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).Alterations; + var filter = alterations[0] as FilterXml; + Assert.That(filter, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy.Cases, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy.Cases.Count, Is.EqualTo(2)); + } + + [Test] + public void Deserialize_RankingWithCases_PredicateOrCombination() + { + int testNr = 2; + + // Create an instance of the XmlSerializer specifying type and namespace. + TestSuiteXml ts = DeserializeSample(); + + Assert.That(ts.Tests[testNr].Systems[0], Is.TypeOf()); + var alterations = (ts.Tests[testNr].Systems[0] as ResultSetSystemXml).Alterations; + var filter = alterations[0] as FilterXml; + Assert.That(filter, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy.Cases[0].Predication, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy.Cases[0].Predication, Is.TypeOf()); + Assert.That(filter.Ranking.GroupBy.Cases[1].Predication, Is.Not.Null); + Assert.That(filter.Ranking.GroupBy.Cases[1].Predication, Is.TypeOf()); + } + } } diff --git a/NBi.Testing.Xml/Resources/RankingXmlTestSuite.xml b/NBi.Testing.Xml/Resources/RankingXmlTestSuite.xml index 636f05090..c7ca3c59e 100644 --- a/NBi.Testing.Xml/Resources/RankingXmlTestSuite.xml +++ b/NBi.Testing.Xml/Resources/RankingXmlTestSuite.xml @@ -50,4 +50,44 @@ + + + + + select row_count as DeptId, [Name], [GroupName] from [HumanResources].[Department] order by Name + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 10 + + + + diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 9543094bf..6d320c101 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -29,7 +29,7 @@ - + + --> + + + + + + + + + + + + CUST0003 + + + + + 100 + + + + + CUST0001 + + + + + + + + + + + + + + + + + CUST0001 + 80 + + + CUST0001 + 100 + + + CUST0002 + 80 + + + CUST0003 + 55 + + + + - + \ No newline at end of file diff --git a/NBi.Testing/Unit/NUnit/Builder/ResultSetAllRowsBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/ResultSetAllRowsBuilderTest.cs index 6fc4cc474..de5d7cad4 100644 --- a/NBi.Testing/Unit/NUnit/Builder/ResultSetAllRowsBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/ResultSetAllRowsBuilderTest.cs @@ -67,7 +67,7 @@ public void GetConstraint_BuildWithResultSet_CorrectConstraint() var ctrXml = new AllRowsXml { - Predication = new PredicationXml() { + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) } @@ -96,7 +96,7 @@ public void GetConstraint_Build_DontEvaluateVariable() var ctrXml = new AllRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -133,7 +133,7 @@ public void GetConstraint_BuildWithVariables_DontEvaluateThem() var ctrXml = new AllRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -171,7 +171,7 @@ public void GetSystemUnderTest_ExecutionXml_IResultSetService() var ctrXml = new AllRowsXml() { - Predication = new PredicationXml() { + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "10" }, Operand = new ColumnOrdinalIdentifier(0) } @@ -195,7 +195,7 @@ public void GetSystemUnderTest_ResultSetSystemXml_IResultSetService() var ctrXml = new AllRowsXml() { - Predication = new PredicationXml() { + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "10" }, Operand = new ColumnOrdinalIdentifier(0) } diff --git a/NBi.Testing/Unit/NUnit/Builder/ResultSetRowCountBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/ResultSetRowCountBuilderTest.cs index 151523cfe..b096a7580 100644 --- a/NBi.Testing/Unit/NUnit/Builder/ResultSetRowCountBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/ResultSetRowCountBuilderTest.cs @@ -95,7 +95,7 @@ public void GetConstraint_RowCountFiltered_CorrectConstraint() Filter = new FilterXml() }; ctrXml.Filter.InternalAliases.Add(new AliasXml()); - ctrXml.Filter.Predication = new PredicationXml() { Predicate = new NullXml(), Operand = new ColumnNameIdentifier("myColumn") }; + ctrXml.Filter.Predication = new SinglePredicationXml() { Predicate = new NullXml(), Operand = new ColumnNameIdentifier("myColumn") }; var builder = new ResultSetRowCountBuilder(); builder.Setup(sutXml, ctrXml, null, null, new ServiceLocator()); @@ -124,7 +124,7 @@ public void GetConstraint_PercentageForRowCount_CorrectConstraint() Filter = new FilterXml() { InternalAliases = new List() { new AliasXml()}, - Predication = new PredicationXml() { Predicate = new NullXml(), Operand = new ColumnNameIdentifier("myColumn") } + Predication = new SinglePredicationXml() { Predicate = new NullXml(), Operand = new ColumnNameIdentifier("myColumn") } } }; diff --git a/NBi.Testing/Unit/NUnit/Builder/ResultSetSingleRowBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/ResultSetSingleRowBuilderTest.cs index 2fae9904a..4e6fda5e2 100644 --- a/NBi.Testing/Unit/NUnit/Builder/ResultSetSingleRowBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/ResultSetSingleRowBuilderTest.cs @@ -67,7 +67,7 @@ public void GetConstraint_BuildWithResultSet_CorrectConstraint() var ctrXml = new SingleRowXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) @@ -97,7 +97,7 @@ public void GetConstraint_Build_DontEvaluateVariable() var ctrXml = new SingleRowXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -133,7 +133,7 @@ public void GetConstraint_BuildWithVariables_DontEvaluateThem() var ctrXml = new SingleRowXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -171,7 +171,7 @@ public void GetSystemUnderTest_ExecutionXml_IResultSetService() var ctrXml = new SingleRowXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) @@ -196,7 +196,7 @@ public void GetSystemUnderTest_ResultSetSystemXml_IResultSetService() var ctrXml = new SingleRowXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) diff --git a/NBi.Testing/Unit/NUnit/Builder/ResultSetSomeRowsBuilderTest.cs b/NBi.Testing/Unit/NUnit/Builder/ResultSetSomeRowsBuilderTest.cs index e6d615927..fe70e578b 100644 --- a/NBi.Testing/Unit/NUnit/Builder/ResultSetSomeRowsBuilderTest.cs +++ b/NBi.Testing/Unit/NUnit/Builder/ResultSetSomeRowsBuilderTest.cs @@ -67,7 +67,7 @@ public void GetConstraint_BuildWithResultSet_CorrectConstraint() var ctrXml = new SomeRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) @@ -97,7 +97,7 @@ public void GetConstraint_Build_DontEvaluateVariable() var ctrXml = new SomeRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -133,7 +133,7 @@ public void GetConstraint_BuildWithVariables_DontEvaluateThem() var ctrXml = new SomeRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "@year" }, Operand = new ColumnOrdinalIdentifier(0) @@ -171,7 +171,7 @@ public void GetSystemUnderTest_ExecutionXml_IResultSetService() var ctrXml = new SomeRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) @@ -196,7 +196,7 @@ public void GetSystemUnderTest_ResultSetSystemXml_IResultSetService() var ctrXml = new SomeRowsXml { - Predication = new PredicationXml() + Predication = new SinglePredicationXml() { Predicate = new MoreThanXml() { Reference = "100" }, Operand = new ColumnOrdinalIdentifier(0) diff --git a/NBi.Xml/Constraints/NoRowsXml.cs b/NBi.Xml/Constraints/NoRowsXml.cs index 1317aab6f..dfe21906a 100644 --- a/NBi.Xml/Constraints/NoRowsXml.cs +++ b/NBi.Xml/Constraints/NoRowsXml.cs @@ -46,10 +46,10 @@ public List InternalAliasesOld private List internalAliases; [XmlElement("predicate", Order = 4)] - public PredicationXml Predication { get; set; } + public SinglePredicationXml Predication { get; set; } [XmlElement("combination", Order = 5)] - public CombinationPredicateXml Combination { get; set; } + public CombinationPredicationXml Combination { get; set; } public NoRowsXml() { diff --git a/NBi.Xml/Items/AbstractPredicationXml.cs b/NBi.Xml/Items/AbstractPredicationXml.cs new file mode 100644 index 000000000..3b18ab0a7 --- /dev/null +++ b/NBi.Xml/Items/AbstractPredicationXml.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Xml.Items +{ + public abstract class AbstractPredicationXml + { } +} diff --git a/NBi.Xml/Items/Calculation/CombinationPredicateXml.cs b/NBi.Xml/Items/Calculation/CombinationPredicationXml.cs similarity index 81% rename from NBi.Xml/Items/Calculation/CombinationPredicateXml.cs rename to NBi.Xml/Items/Calculation/CombinationPredicationXml.cs index ce765da92..ea07fe541 100644 --- a/NBi.Xml/Items/Calculation/CombinationPredicateXml.cs +++ b/NBi.Xml/Items/Calculation/CombinationPredicationXml.cs @@ -12,7 +12,7 @@ namespace NBi.Xml.Items.Calculation { - public class CombinationPredicateXml + public class CombinationPredicationXml : AbstractPredicationXml { [XmlAttribute("operator")] public CombinationOperator Operator { get; set; } @@ -22,6 +22,6 @@ public class CombinationPredicateXml public bool Not { get; set; } [XmlElement("predicate")] - public List Predications { get; set; } + public List Predications { get; set; } } } diff --git a/NBi.Xml/Items/Calculation/FilterXml.cs b/NBi.Xml/Items/Calculation/FilterXml.cs index f6768f14a..51b8accc2 100644 --- a/NBi.Xml/Items/Calculation/FilterXml.cs +++ b/NBi.Xml/Items/Calculation/FilterXml.cs @@ -44,13 +44,13 @@ public List InternalAliasesOld public ExpressionXml Expression { get; set; } [XmlElement("predicate")] - public PredicationXml Predication { get; set; } + public SinglePredicationXml Predication { get; set; } [XmlElement("ranking")] public RankingXml Ranking { get; set; } [XmlElement("combination")] - public CombinationPredicateXml Combination { get; set; } + public CombinationPredicationXml Combination { get; set; } //[XmlElement("ranking")] //public RankingXml Ranking { get; set; } diff --git a/NBi.Xml/Items/Calculation/Grouping/CaseXml.cs b/NBi.Xml/Items/Calculation/Grouping/CaseXml.cs new file mode 100644 index 000000000..b3914c583 --- /dev/null +++ b/NBi.Xml/Items/Calculation/Grouping/CaseXml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace NBi.Xml.Items.Calculation.Grouping +{ + public class CaseXml + { + [XmlElement(Type = typeof(SinglePredicationXml), ElementName = "predicate"), + XmlElement(Type = typeof(CombinationPredicationXml), ElementName = "combination"),] + public AbstractPredicationXml Predication { get; set; } + } +} diff --git a/NBi.Xml/Items/Calculation/Grouping/GroupByxml.cs b/NBi.Xml/Items/Calculation/Grouping/GroupByxml.cs index 41ccd2213..068f64bea 100644 --- a/NBi.Xml/Items/Calculation/Grouping/GroupByxml.cs +++ b/NBi.Xml/Items/Calculation/Grouping/GroupByxml.cs @@ -13,6 +13,9 @@ public class GroupByXml { [XmlElement("column")] public List Columns { get; set; } = new List(); + + [XmlElement("case")] + public List Cases { get; set; } public static GroupByXml None { get; } = new GroupByNone(); diff --git a/NBi.Xml/Items/Calculation/PredicationXml.cs b/NBi.Xml/Items/Calculation/SinglePredicationXml.cs similarity index 96% rename from NBi.Xml/Items/Calculation/PredicationXml.cs rename to NBi.Xml/Items/Calculation/SinglePredicationXml.cs index 66122b4e4..c9969af79 100644 --- a/NBi.Xml/Items/Calculation/PredicationXml.cs +++ b/NBi.Xml/Items/Calculation/SinglePredicationXml.cs @@ -13,7 +13,7 @@ namespace NBi.Xml.Items.Calculation { - public class PredicationXml : BasePredicationXml + public class SinglePredicationXml : BasePredicationXml { [XmlIgnore()] [XmlAttribute("column-index")] @@ -41,7 +41,7 @@ public string OperandSerialized } - public abstract class BasePredicationXml + public abstract class BasePredicationXml : AbstractPredicationXml { public BasePredicationXml() { diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 156259326..2d3384c94 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -150,6 +150,7 @@ + @@ -180,7 +181,8 @@ - + + @@ -266,7 +268,7 @@ - + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 24db9a51e..51a4e7bb8 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1453,9 +1453,20 @@ - - - + + + + + + + + + + + + + + diff --git a/NBi.Xml/SerializationOption/ReadOnlyAttributes.cs b/NBi.Xml/SerializationOption/ReadOnlyAttributes.cs index f47910e5a..1c348d85e 100644 --- a/NBi.Xml/SerializationOption/ReadOnlyAttributes.cs +++ b/NBi.Xml/SerializationOption/ReadOnlyAttributes.cs @@ -33,7 +33,7 @@ protected override void AdditionalBuild() AddAsAttribute((ConnectionWaitXml c) => c.SpecificConnectionStringOld, "connectionString"); AddAsAttribute((DataManipulationAbstractXml x) => x.SpecificConnectionStringOld, "connectionString"); AddAsAttribute((SqlRunXml x) => x.SpecificConnectionStringOld, "connectionString"); - AddAsAttribute((PredicationXml p) => p.Name, "name"); + AddAsAttribute((SinglePredicationXml p) => p.Name, "name"); AddAsAttribute((ResultSetSystemXml r) => r.FilePath, "file"); AddAsElement((NoRowsXml c) => c.InternalAliasesOld, "variable", 2); @@ -44,7 +44,7 @@ protected override void AdditionalBuild() AddAsText((FileXml x) => x.Value); - AddToElements((PredicationXml p) => p.Predicate, "within-list", typeof(WithinListXml)); + AddToElements((SinglePredicationXml p) => p.Predicate, "within-list", typeof(WithinListXml)); AddToElements((ProjectionOldXml x) => x.ResultSetOld, "resultSet", typeof(ResultSetSystemXml)); AddToElements((LookupExistsXml x) => x.ResultSetOld, "resultSet", typeof(ResultSetSystemXml)); From 03fe1dc9f74ca5702cf98c04573271ee83db87d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 24 Nov 2019 15:51:59 +0100 Subject: [PATCH 29/57] [WIP] --- .../IO/Commands/FolderExistsCondition.cs | 42 +++++++++++++++++++ .../IO/FolderExistsConditionArgs.cs | 19 +++++++++ NBi.Core/Decoration/IO/IIoConditionArgs.cs | 10 +++++ NBi.Core/NBi.Core.csproj | 3 ++ 4 files changed, 74 insertions(+) create mode 100644 NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs create mode 100644 NBi.Core/Decoration/IO/FolderExistsConditionArgs.cs create mode 100644 NBi.Core/Decoration/IO/IIoConditionArgs.cs diff --git a/NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs b/NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs new file mode 100644 index 000000000..aae492559 --- /dev/null +++ b/NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using NBi.Core.Decoration.IO; +using System.Diagnostics; +using NBi.Extensibility; + +namespace NBi.Core.Decoration.IO.Commands +{ + class FolderExistsCondition : IDecorationCondition + { + private FolderExistsConditionArgs Args { get; } + + public string Message => throw new NotImplementedException(); + + public FolderExistsCondition(FolderExistsConditionArgs args) => Args = args; + + public bool Validate() + { + var path = PathExtensions.CombineOrRoot(Args.BasePath, Args.FolderPath.Execute()); + var fullPath = PathExtensions.CombineOrRoot(path, Args.FolderName.Execute()); + + var conditions = new List>() { ExistsCondition }; + if (Args.NotEmpty.Execute()) + conditions.Add(IsEmptyCondition); + + var result = true; + var enumerator = conditions.GetEnumerator(); + while (result && enumerator.MoveNext()) + result = enumerator.Current.Invoke(fullPath); + return result; + } + + protected bool ExistsCondition(string fullPath) + => Directory.Exists(fullPath); + + protected bool IsEmptyCondition(string fullPath) + => !string.IsNullOrEmpty(Directory.EnumerateFiles(fullPath).FirstOrDefault()); + } +} diff --git a/NBi.Core/Decoration/IO/FolderExistsConditionArgs.cs b/NBi.Core/Decoration/IO/FolderExistsConditionArgs.cs new file mode 100644 index 000000000..77d5c6d56 --- /dev/null +++ b/NBi.Core/Decoration/IO/FolderExistsConditionArgs.cs @@ -0,0 +1,19 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NBi.Core.Decoration.IO +{ + public class FolderExistsConditionArgs : IIoConditionArgs + { + public string BasePath { get; } + public IScalarResolver FolderName { get; } + public IScalarResolver FolderPath { get; } + public IScalarResolver NotEmpty { get; } + + public FolderExistsConditionArgs(string basePath, IScalarResolver folderPath, IScalarResolver folderName, IScalarResolver notEmpty) + => (BasePath, FolderPath, FolderName, NotEmpty) = (basePath, folderPath, folderName, notEmpty); + } +} diff --git a/NBi.Core/Decoration/IO/IIoConditionArgs.cs b/NBi.Core/Decoration/IO/IIoConditionArgs.cs new file mode 100644 index 000000000..a6338e0e5 --- /dev/null +++ b/NBi.Core/Decoration/IO/IIoConditionArgs.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NBi.Core.Decoration.IO +{ + public interface IIoConditionArgs : IDecorationConditionArgs + { } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 595d5c3ad..04c2ae7a1 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -149,6 +149,9 @@ + + + From 3128ce124190fd2745ea4dc7c0a0a4b703c1ef43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 1 Dec 2019 16:50:26 +0100 Subject: [PATCH 30/57] Implement query-sequence for variables defined in instance-settling and fix a few things for custom --- NBi.Core/NBi.Core.csproj | 2 + NBi.Core/Query/EngineFactory.cs | 2 +- .../Execution/DbCommandExecutionEngine.cs | 2 +- .../Query/Resolver/QueryResolverFactory.cs | 2 +- .../Resolver/QuerySequenceResolver.cs | 50 +++++++++++++ .../Resolver/QuerySequenceResolverArgs.cs | 21 ++++++ .../Resolver/SequenceResolverFactory.cs | 12 +-- .../Builder/Helper/InstanceArgsBuilder.cs | 6 +- .../Helper/SequenceResolverArgsBuilder.cs | 34 +++++---- NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + .../Resolver/QuerySequenceResolverTest.cs | 75 +++++++++++++++++++ NBi.Testing.Xml/NBi.Testing.Xml.csproj | 4 + .../Resources/QuerySequenceXmlTestSuite.xml | 28 +++++++ .../Sequence/QuerySequenceXmlTest.cs | 45 +++++++++++ .../Resources/Positive/MultipleInstance.nbits | 25 ++++++- NBi.Xml/Schema/BaseType.xsd | 1 + NBi.Xml/Variables/Sequence/SequenceXml.cs | 4 + 17 files changed, 287 insertions(+), 27 deletions(-) create mode 100644 NBi.Core/Sequence/Resolver/QuerySequenceResolver.cs create mode 100644 NBi.Core/Sequence/Resolver/QuerySequenceResolverArgs.cs create mode 100644 NBi.Testing.Core/Sequence/Resolver/QuerySequenceResolverTest.cs create mode 100644 NBi.Testing.Xml/Resources/QuerySequenceXmlTestSuite.xml create mode 100644 NBi.Testing.Xml/Variables/Sequence/QuerySequenceXmlTest.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 04c2ae7a1..1ef09debb 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -747,6 +747,8 @@ + + diff --git a/NBi.Core/Query/EngineFactory.cs b/NBi.Core/Query/EngineFactory.cs index bd80fb616..1b9cf1bce 100644 --- a/NBi.Core/Query/EngineFactory.cs +++ b/NBi.Core/Query/EngineFactory.cs @@ -43,7 +43,7 @@ protected internal void RegisterEngines(Type[] types) throw new ArgumentException($"Unable to find the attribute SupportedCommandType for the type{(invalidTypes.Count>1 ? "s" : string.Empty)}: '{string.Join(@"', '", invalidTypes)}'."); } - public T Instantiate(IQuery query) + public virtual T Instantiate(IQuery query) { var session = sessionFactory.Instantiate(query.ConnectionString); var cmd = commandFactory.Instantiate(session, query); diff --git a/NBi.Core/Query/Execution/DbCommandExecutionEngine.cs b/NBi.Core/Query/Execution/DbCommandExecutionEngine.cs index 95664bd52..ee28cc489 100644 --- a/NBi.Core/Query/Execution/DbCommandExecutionEngine.cs +++ b/NBi.Core/Query/Execution/DbCommandExecutionEngine.cs @@ -97,7 +97,7 @@ protected virtual IEnumerable OnExecuteList(IDbCommand command) { var dr = command.ExecuteReader(); while (dr.Read()) - list.Add((T)dr.GetValue(0)); + list.Add((T)Convert.ChangeType(dr.GetValue(0), typeof(T))); } catch (Exception ex) { HandleException(ex, command); } diff --git a/NBi.Core/Query/Resolver/QueryResolverFactory.cs b/NBi.Core/Query/Resolver/QueryResolverFactory.cs index e6a5f3e37..c8abb78b4 100644 --- a/NBi.Core/Query/Resolver/QueryResolverFactory.cs +++ b/NBi.Core/Query/Resolver/QueryResolverFactory.cs @@ -16,7 +16,7 @@ public QueryResolverFactory(ServiceLocator serviceLocator) this.serviceLocator = serviceLocator; } - public IQueryResolver Instantiate(BaseQueryResolverArgs args) + public virtual IQueryResolver Instantiate(BaseQueryResolverArgs args) { if (args is AssemblyQueryResolverArgs) return new AssemblyQueryResolver((AssemblyQueryResolverArgs)args); diff --git a/NBi.Core/Sequence/Resolver/QuerySequenceResolver.cs b/NBi.Core/Sequence/Resolver/QuerySequenceResolver.cs new file mode 100644 index 000000000..daaf58582 --- /dev/null +++ b/NBi.Core/Sequence/Resolver/QuerySequenceResolver.cs @@ -0,0 +1,50 @@ +using NBi.Core.Injection; +using NBi.Core.Query; +using NBi.Core.Query.Execution; +using NBi.Core.Query.Resolver; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Extensibility.Query; +using System.Collections; + +namespace NBi.Core.Sequence.Resolver +{ + class QuerySequenceResolver : ISequenceResolver + { + private QuerySequenceResolverArgs Args { get; } + private ServiceLocator ServiceLocator { get; } + + public QuerySequenceResolver(QuerySequenceResolverArgs args, ServiceLocator serviceLocator) + => (Args, ServiceLocator) = (args, serviceLocator); + + protected virtual IQuery ResolveQuery() + { + var factory = ServiceLocator.GetQueryResolverFactory(); + var resolver = factory.Instantiate(Args.QueryArgs); + var query = resolver.Execute(); + return query; + } + + protected virtual IEnumerable ExecuteQuery(IQuery query) + { + var factory = ServiceLocator.GetExecutionEngineFactory(); + var queryEngine = factory.Instantiate(query); + var value = queryEngine.ExecuteList(); + return value; + } + + public List Execute() + { + var cmd = ResolveQuery(); + var value = ExecuteQuery(cmd); + return value.ToList(); + } + + object IResolver.Execute() => Execute(); + IList ISequenceResolver.Execute() => Execute(); + } +} diff --git a/NBi.Core/Sequence/Resolver/QuerySequenceResolverArgs.cs b/NBi.Core/Sequence/Resolver/QuerySequenceResolverArgs.cs new file mode 100644 index 000000000..c20b9e11e --- /dev/null +++ b/NBi.Core/Sequence/Resolver/QuerySequenceResolverArgs.cs @@ -0,0 +1,21 @@ +using NBi.Core.Query; +using NBi.Core.Query.Resolver; +using NBi.Core.ResultSet.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Resolver +{ + public class QuerySequenceResolverArgs : ISequenceResolverArgs + { + public BaseQueryResolverArgs QueryArgs { get; } + + public QuerySequenceResolverArgs(BaseQueryResolverArgs args) + { + this.QueryArgs = args; + } + } +} diff --git a/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs b/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs index 20b474eba..f9970e410 100644 --- a/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs +++ b/NBi.Core/Sequence/Resolver/SequenceResolverFactory.cs @@ -12,17 +12,17 @@ namespace NBi.Core.Sequence.Resolver { public class SequenceResolverFactory { - private readonly ServiceLocator serviceLocator; + private ServiceLocator ServiceLocator { get; } public SequenceResolverFactory(ServiceLocator serviceLocator) - { - this.serviceLocator = serviceLocator; - } - + => ServiceLocator = serviceLocator; + internal ISequenceResolver Instantiate(ISequenceResolverArgs args) { switch (args) { + case QuerySequenceResolverArgs queryArgs: return new QuerySequenceResolver(queryArgs, ServiceLocator); case ListSequenceResolverArgs listArgs: return new ListSequenceResolver(listArgs); + case CustomSequenceResolverArgs customArgs: return new CustomSequenceResolver(customArgs); case FileLoopSequenceResolverArgs fileArgs: return (ISequenceResolver)new FileLoopSequenceResolver(fileArgs); case ILoopSequenceResolverArgs loopArgs: { @@ -31,7 +31,7 @@ internal ISequenceResolver Instantiate(ISequenceResolverArgs args) } case FilterSequenceResolverArgs filterArgs: return new FilterSequenceResolver(filterArgs); default: - throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a Scalar"); + throw new ArgumentOutOfRangeException($"Type '{args.GetType().Name}' is not expected when building a Sequence"); } } diff --git a/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs b/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs index 549abd8a3..ca3866ca0 100644 --- a/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/InstanceArgsBuilder.cs @@ -63,7 +63,11 @@ public void Build() argsBuilder.Setup(variable.SentinelLoop); else if (variable.FileLoop != null) argsBuilder.Setup(variable.FileLoop); - else if (variable.Items != null) + else if (variable.Custom != null) + argsBuilder.Setup(variable.Custom); + else if (variable.Query != null) + argsBuilder.Setup(variable.Query); + else if (variable.Items != null && variable.Items.Count>0) argsBuilder.Setup(variable.Items); else throw new ArgumentOutOfRangeException(); diff --git a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs index 91d7270dd..0e8e37a7c 100644 --- a/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/SequenceResolverArgsBuilder.cs @@ -6,6 +6,7 @@ using NBi.Core.Sequence.Resolver; using NBi.Core.Sequence.Resolver.Loop; using NBi.Core.Variable; +using NBi.Xml.Items; using NBi.Xml.Settings; using NBi.Xml.Variables.Custom; using NBi.Xml.Variables.Sequence; @@ -26,15 +27,14 @@ class SequenceResolverArgsBuilder private object obj = null; private SettingsXml settings = null; private IDictionary Variables { get; set; } = new Dictionary(); - private ISequenceResolverArgs args = null; + private SettingsXml.DefaultScope Scope { get; } = SettingsXml.DefaultScope.Everywhere; + private ISequenceResolverArgs Args { get; set; } = null; private ColumnType columnType = ColumnType.Numeric; - private readonly ServiceLocator serviceLocator; + private ServiceLocator ServiceLocator { get; } public SequenceResolverArgsBuilder(ServiceLocator serviceLocator) - { - this.serviceLocator = serviceLocator; - } + => ServiceLocator = serviceLocator; public void Setup(object obj) { @@ -62,27 +62,33 @@ public void Build() if (!isSetup) throw new InvalidOperationException(); - var helper = new ScalarHelper(serviceLocator, new Context(Variables)); + var helper = new ScalarHelper(ServiceLocator, new Context(Variables)); switch (obj) { case SentinelLoopXml loop: switch (columnType) { case ColumnType.Numeric: - args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); + Args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); break; case ColumnType.DateTime: - args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); + Args = BuildSentinelLoopResolverArgs(loop.Seed, loop.Terminal, loop.Step, loop.IntervalMode); break; default: throw new ArgumentOutOfRangeException(); } break; case FileLoopXml loop: - args = BuildFileLoopResolverArgs(loop.Path, loop.Pattern); + Args = BuildFileLoopResolverArgs(loop.Path, loop.Pattern); + break; + case QueryXml query: + var queryBuilder = new QueryResolverArgsBuilder(ServiceLocator); + queryBuilder.Setup(query, settings, Scope, Variables); + queryBuilder.Build(); + Args = new QuerySequenceResolverArgs(queryBuilder.GetArgs()); break; case CustomXml obj: - args = new CustomSequenceResolverArgs( + Args = new CustomSequenceResolverArgs( helper.InstantiateResolver(obj.AssemblyPath), helper.InstantiateResolver(obj.TypeName), obj.Parameters.Select(x => new { x.Name, ScalarResolver = (IScalarResolver)helper.InstantiateResolver(x.StringValue) }) @@ -93,18 +99,18 @@ public void Build() var resolvers = new List(); foreach (var value in list) resolvers.Add(helper.InstantiateResolver(value)); - args = new ListSequenceResolverArgs(resolvers); + Args = new ListSequenceResolverArgs(resolvers); break; default: throw new ArgumentOutOfRangeException(); } } - public ISequenceResolverArgs GetArgs() => args ?? throw new InvalidOperationException(); + public ISequenceResolverArgs GetArgs() => Args ?? throw new InvalidOperationException(); private ISequenceResolverArgs BuildSentinelLoopResolverArgs(string seed, string terminal, string step, IntervalMode intervalMode) { - var helper = new ScalarHelper(serviceLocator, new Context(Variables)); + var helper = new ScalarHelper(ServiceLocator, new Context(Variables)); var args = new SentinelLoopSequenceResolverArgs( helper.InstantiateResolver(seed).Execute(), @@ -117,7 +123,7 @@ private ISequenceResolverArgs BuildSentinelLoopResolverArgs(string seed, s } private ISequenceResolverArgs BuildFileLoopResolverArgs(string path, string pattern) { - var helper = new ScalarHelper(serviceLocator, new Context(Variables)); + var helper = new ScalarHelper(ServiceLocator, new Context(Variables)); var args = new FileLoopSequenceResolverArgs() { diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 804ad143f..666e5f4b6 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -234,6 +234,7 @@ + diff --git a/NBi.Testing.Core/Sequence/Resolver/QuerySequenceResolverTest.cs b/NBi.Testing.Core/Sequence/Resolver/QuerySequenceResolverTest.cs new file mode 100644 index 000000000..0d66acbee --- /dev/null +++ b/NBi.Testing.Core/Sequence/Resolver/QuerySequenceResolverTest.cs @@ -0,0 +1,75 @@ +using Moq; +using NBi.Core.Injection; +using NBi.Core.Query.Execution; +using NBi.Core.Query.Resolver; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Resolver; +using NBi.Extensibility.Query; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Core.Sequence.Resolver +{ + [TestFixture] + public class QuerySequenceResolverTest + { + [Test] + public void Execute_QueryEmbedded_CorrectlyExecuted() + { + var queryArgs = new EmbeddedQueryResolverArgs( + "select * from table" + , "server=.;initiatl catalog=db;integrated security=true" + , null + , null + , new TimeSpan(0, 0, 30) + ); + var args = new QuerySequenceResolverArgs(queryArgs); + + var executionEngine = Mock.Of(x => x.ExecuteList() == new List() { "foo", "bar" }); + var executionEngineFactory = Mock.Of(x => x.Instantiate(It.IsAny()) == executionEngine); + var queryResolverFactory = new ServiceLocator().GetQueryResolverFactory(); + + var serviceLocator = Mock.Of( + x => x.GetExecutionEngineFactory() == executionEngineFactory + && x.GetQueryResolverFactory() == queryResolverFactory + ); + + var resolver = new QuerySequenceResolver(args, serviceLocator); + var elements = resolver.Execute(); + Assert.That(elements.Count(), Is.EqualTo(2)); + Assert.That(elements, Has.Member("foo")); + Assert.That(elements, Has.Member("bar")); + } + + [Test] + public void Execute_QueryEmbedded_CorrectCallsToServiceLocatorMethods() + { + var queryArgs = new EmbeddedQueryResolverArgs( + "select * from table" + , "server=.;initiatl catalog=db;integrated security=true" + , null + , null + , new TimeSpan(0, 0, 30) + ); + var args = new QuerySequenceResolverArgs(queryArgs); + + var executionEngine = Mock.Of(x => x.ExecuteList() == new List() { "foo", "bar" }); + var executionEngineFactory = Mock.Of(x => x.Instantiate(It.IsAny()) == executionEngine); + var queryResolverFactory = new ServiceLocator().GetQueryResolverFactory(); + + var serviceLocator = Mock.Of( + x => x.GetExecutionEngineFactory() == executionEngineFactory + && x.GetQueryResolverFactory() == queryResolverFactory + ); + + var resolver = new QuerySequenceResolver(args, serviceLocator); + var elements = resolver.Execute(); + Mock.Get(executionEngine).Verify(x => x.ExecuteList(), Times.Once); + Mock.Get(executionEngineFactory).Verify(x => x.Instantiate(It.IsAny()), Times.Once); + } + } +} diff --git a/NBi.Testing.Xml/NBi.Testing.Xml.csproj b/NBi.Testing.Xml/NBi.Testing.Xml.csproj index b8f23628b..97da65c91 100644 --- a/NBi.Testing.Xml/NBi.Testing.Xml.csproj +++ b/NBi.Testing.Xml/NBi.Testing.Xml.csproj @@ -118,6 +118,7 @@ + @@ -419,6 +420,9 @@ + + + diff --git a/NBi.Testing.Xml/Resources/QuerySequenceXmlTestSuite.xml b/NBi.Testing.Xml/Resources/QuerySequenceXmlTestSuite.xml new file mode 100644 index 000000000..533d6a800 --- /dev/null +++ b/NBi.Testing.Xml/Resources/QuerySequenceXmlTestSuite.xml @@ -0,0 +1,28 @@ + + + + + Data Source=mhknbn2kdz.database.windows.net;Initial Catalog=AdventureWorks2012;User Id=sqlfamily;password=sqlf@m1ly + + + + + + + select [mycolumn] from myTable where [myFilter]=@filter + filterValue + + + + + + + + + + + + + + + diff --git a/NBi.Testing.Xml/Variables/Sequence/QuerySequenceXmlTest.cs b/NBi.Testing.Xml/Variables/Sequence/QuerySequenceXmlTest.cs new file mode 100644 index 000000000..db9e6d7cd --- /dev/null +++ b/NBi.Testing.Xml/Variables/Sequence/QuerySequenceXmlTest.cs @@ -0,0 +1,45 @@ +using NBi.Xml; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Xml.Variables; +using System.Xml.Serialization; +using System.IO; +using System.Diagnostics; +using NBi.Xml.Items; +using System.Reflection; +using NBi.Core.ResultSet; +using NBi.Xml.Variables.Sequence; +using NBi.Core.Calculation; + +namespace NBi.Testing.Xml.Unit.Variables.Sequence +{ + public class QuerySequenceXmlTest : BaseXmlTest + { + + [Test] + public void Deserialize_SampleFile_VariableHasFileLoop() + { + var ts = DeserializeSample(); + var variable = ts.Tests[0].InstanceSettling.Variable as InstanceVariableXml; + + // Check the properties of the object. + Assert.That(variable.Query, Is.Not.Null); + Assert.That(variable.Query, Is.TypeOf()); + } + + [Test] + public void Deserialize_SampleFile_VariableHasCorrectNameAndType() + { + var ts = DeserializeSample(); + var variable = ts.Tests[0].InstanceSettling.Variable as InstanceVariableXml; + + // Check the properties of the object. + Assert.That(variable.Query.InlineQuery, Does.Contain(@"select [mycolumn] from myTable where [myFilter]=@filter")); + Assert.That(variable.Query.Parameters, Has.Count.EqualTo(1)); + } + } +} diff --git a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits index 6c6156402..5644f9127 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/MultipleInstance.nbits @@ -299,7 +299,7 @@ - + @@ -388,14 +388,33 @@ --> - + - + + + + + + + + + + + + + + + select '2016-01-01' union all select '2016-02-01' union all select '2016-03-01' + + + + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 51a4e7bb8..6c0fdc66c 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -1289,6 +1289,7 @@ + diff --git a/NBi.Xml/Variables/Sequence/SequenceXml.cs b/NBi.Xml/Variables/Sequence/SequenceXml.cs index 1b531a2cf..dc5a14e33 100644 --- a/NBi.Xml/Variables/Sequence/SequenceXml.cs +++ b/NBi.Xml/Variables/Sequence/SequenceXml.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Xml.Items; using NBi.Xml.Variables.Custom; using System; using System.Collections.Generic; @@ -23,6 +24,9 @@ public class SequenceXml [XmlElement("item")] public List Items { get; set; } = new List(); + [XmlElement("query-sequence")] + public QueryXml Query { get; set; } + [XmlElement("loop-file")] public FileLoopXml FileLoop { get; set; } From e7ab553f50d16a145711508da062f32d21573839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 1 Dec 2019 18:17:19 +0100 Subject: [PATCH 31/57] Add support for variables when evaluating an expression --- NBi.Core/Calculation/RowValueExtractor.cs | 4 ++- .../Resources/Positive/QueryAllNoRows.nbits | 30 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/NBi.Core/Calculation/RowValueExtractor.cs b/NBi.Core/Calculation/RowValueExtractor.cs index a116d75a3..735bd934a 100644 --- a/NBi.Core/Calculation/RowValueExtractor.cs +++ b/NBi.Core/Calculation/RowValueExtractor.cs @@ -72,7 +72,9 @@ protected object EvaluateExpression(IColumnExpression expression, Context contex exp.EvaluateParameter += delegate (string name, NCalc.ParameterArgs args) { - args.Result = Execute(context, factory.Instantiate(name)); + args.Result = name.StartsWith("@") + ? context.Variables[name.Substring(1, name.Length-1)].GetValue() + : Execute(context, factory.Instantiate(name)); }; return exp.Evaluate(); diff --git a/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits b/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits index bf61caadf..2302e2504 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/QueryAllNoRows.nbits @@ -22,6 +22,11 @@ DateTime.Now.AddDays(-2) + + + @@ -638,7 +643,7 @@ - + - + + + + + select 10 as 'A' ,11 as 'B', 12 as 'C' + union all select 5,6,7 + union all select 7,8,9 + + + + + + [@myVar] * [#0] * [C] + + 10000 + + + + + Date: Thu, 5 Dec 2019 23:41:56 +0100 Subject: [PATCH 32/57] Add support for variables in alteration extend and native and ncalc engines --- .../Extension/AbstractExtendEngine.cs | 6 +- .../Alteration/Extension/ExtensionFactory.cs | 10 +-- .../Alteration/Extension/NCalcExtendEngine.cs | 8 ++- .../Extension/NativeExtendEngine.cs | 9 ++- .../Scalar/Resolver/NCalcScalarResolver.cs | 4 +- .../Resolver/NCalcScalarResolverArgs.cs | 7 +- .../Builder/Helper/ResultSetSystemHelper.cs | 2 +- .../Extension/ExtensionFactoryTest.cs | 5 +- .../Extension/NCalcExtendEngineTest.cs | 29 ++++++++ .../Extension/NativeExtendEngineTest.cs | 54 +++++++++++++++ .../Resolver/NCalcScalarResolverTest.cs | 37 ++++++++-- .../Resolver/ScalarResolverFactoryTest.cs | 13 ++-- .../Positive/ResultSetConstraint.nbits | 68 ++++++++++++++++--- 13 files changed, 211 insertions(+), 41 deletions(-) diff --git a/NBi.Core/ResultSet/Alteration/Extension/AbstractExtendEngine.cs b/NBi.Core/ResultSet/Alteration/Extension/AbstractExtendEngine.cs index b48415699..79757edc9 100644 --- a/NBi.Core/ResultSet/Alteration/Extension/AbstractExtendEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Extension/AbstractExtendEngine.cs @@ -1,5 +1,6 @@ using NBi.Core.Injection; using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Data; @@ -12,11 +13,12 @@ namespace NBi.Core.ResultSet.Alteration.Extension abstract class AbstractExtendEngine : IExtensionEngine { protected ServiceLocator ServiceLocator { get; } + protected Context Context { get; } protected IColumnIdentifier NewColumn { get; } protected string Code { get; } - public AbstractExtendEngine(ServiceLocator serviceLocator, IColumnIdentifier newColumn, string code) - => (ServiceLocator, NewColumn, Code) = (serviceLocator, newColumn, code); + public AbstractExtendEngine(ServiceLocator serviceLocator, Context context, IColumnIdentifier newColumn, string code) + => (ServiceLocator, Context, NewColumn, Code) = (serviceLocator, context, newColumn, code); public ResultSet Execute(ResultSet rs) { diff --git a/NBi.Core/ResultSet/Alteration/Extension/ExtensionFactory.cs b/NBi.Core/ResultSet/Alteration/Extension/ExtensionFactory.cs index 71f603cc4..ee305dff4 100644 --- a/NBi.Core/ResultSet/Alteration/Extension/ExtensionFactory.cs +++ b/NBi.Core/ResultSet/Alteration/Extension/ExtensionFactory.cs @@ -1,5 +1,6 @@ using NBi.Core.Injection; using NBi.Core.Transformation; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Linq; @@ -11,9 +12,10 @@ namespace NBi.Core.ResultSet.Alteration.Extension public class ExtensionFactory { protected ServiceLocator ServiceLocator { get; } + protected Context Context { get; } - public ExtensionFactory(ServiceLocator serviceLocator) - => ServiceLocator = serviceLocator; + public ExtensionFactory(ServiceLocator serviceLocator, Context context) + => (ServiceLocator, Context) = (serviceLocator, context); public IExtensionEngine Instantiate(IExtensionArgs args) { @@ -22,8 +24,8 @@ public IExtensionEngine Instantiate(IExtensionArgs args) case ExtendArgs x: switch (x.Language) { - case LanguageType.NCalc: return new NCalcExtendEngine(ServiceLocator, x.NewColumn, x.Code); - case LanguageType.Native: return new NativeExtendEngine(ServiceLocator, x.NewColumn, x.Code); + case LanguageType.NCalc: return new NCalcExtendEngine(ServiceLocator, Context, x.NewColumn, x.Code); + case LanguageType.Native: return new NativeExtendEngine(ServiceLocator, Context, x.NewColumn, x.Code); default: throw new ArgumentException(); } default: throw new ArgumentException(); diff --git a/NBi.Core/ResultSet/Alteration/Extension/NCalcExtendEngine.cs b/NBi.Core/ResultSet/Alteration/Extension/NCalcExtendEngine.cs index 19662fd04..a7149d8d3 100644 --- a/NBi.Core/ResultSet/Alteration/Extension/NCalcExtendEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Extension/NCalcExtendEngine.cs @@ -1,5 +1,6 @@ using NBi.Core.Injection; using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; using System; using System.Collections.Generic; using System.Data; @@ -11,14 +12,15 @@ namespace NBi.Core.ResultSet.Alteration.Extension { class NCalcExtendEngine : AbstractExtendEngine { - public NCalcExtendEngine(ServiceLocator serviceLocator, IColumnIdentifier newColumn, string code) - : base(serviceLocator, newColumn, code) { } + public NCalcExtendEngine(ServiceLocator serviceLocator, Context context, IColumnIdentifier newColumn, string code) + : base(serviceLocator, context, newColumn, code) { } protected override ResultSet Execute(ResultSet rs, int ordinal) { foreach (DataRow row in rs.Rows) { - var args = new NCalcScalarResolverArgs(Code, row); + Context.Switch(row); + var args = new NCalcScalarResolverArgs(Code, Context); var resolver = new NCalcScalarResolver(args); row[ordinal] = resolver.Execute(); } diff --git a/NBi.Core/ResultSet/Alteration/Extension/NativeExtendEngine.cs b/NBi.Core/ResultSet/Alteration/Extension/NativeExtendEngine.cs index 3c1747c53..cef8cac0a 100644 --- a/NBi.Core/ResultSet/Alteration/Extension/NativeExtendEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Extension/NativeExtendEngine.cs @@ -12,20 +12,19 @@ namespace NBi.Core.ResultSet.Alteration.Extension { class NativeExtendEngine : AbstractExtendEngine { - public NativeExtendEngine(ServiceLocator serviceLocator, IColumnIdentifier newColumn, string code) - : base(serviceLocator, newColumn, code) { } + public NativeExtendEngine(ServiceLocator serviceLocator, Context context, IColumnIdentifier newColumn, string code) + : base(serviceLocator, context, newColumn, code) { } protected override ResultSet Execute(ResultSet rs, int ordinal) { - var context = new Context(null); - var argsFactory = new ScalarResolverArgsFactory(ServiceLocator, context); + var argsFactory = new ScalarResolverArgsFactory(ServiceLocator, Context); var args = argsFactory.Instantiate(Code); var factory = ServiceLocator.GetScalarResolverFactory(); var resolver = factory.Instantiate(args); foreach (DataRow row in rs.Rows) { - context.Switch(row); + Context.Switch(row); row[ordinal] = resolver.Execute(); } return rs; diff --git a/NBi.Core/Scalar/Resolver/NCalcScalarResolver.cs b/NBi.Core/Scalar/Resolver/NCalcScalarResolver.cs index 30b5bf02e..9accb39e4 100644 --- a/NBi.Core/Scalar/Resolver/NCalcScalarResolver.cs +++ b/NBi.Core/Scalar/Resolver/NCalcScalarResolver.cs @@ -25,7 +25,9 @@ public T Execute() exp.EvaluateParameter += delegate (string name, NCalc.ParameterArgs args) { - args.Result = GetValueFromRow(Args.Row, factory.Instantiate(name)); + args.Result = name.StartsWith("@") + ? Args.Context.Variables[name.Substring(1, name.Length - 1)].GetValue() + : GetValueFromRow(Args.Context.CurrentRow, factory.Instantiate(name)); }; var rawValue = exp.Evaluate(); diff --git a/NBi.Core/Scalar/Resolver/NCalcScalarResolverArgs.cs b/NBi.Core/Scalar/Resolver/NCalcScalarResolverArgs.cs index 99d8f9f91..389e3b581 100644 --- a/NBi.Core/Scalar/Resolver/NCalcScalarResolverArgs.cs +++ b/NBi.Core/Scalar/Resolver/NCalcScalarResolverArgs.cs @@ -4,16 +4,17 @@ using System.Text; using System.Data; using System.Threading.Tasks; +using NBi.Core.Variable; namespace NBi.Core.Scalar.Resolver { class NCalcScalarResolverArgs : IScalarResolverArgs { public string Code { get; } - public DataRow Row { get; } + public Context Context { get; } - public NCalcScalarResolverArgs(string code, DataRow row) - => (Code, Row) = (code, row); + public NCalcScalarResolverArgs(string code, Context context) + => (Code, Context) = (code, context); } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs index ecb3fd00b..5642778c9 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs @@ -223,7 +223,7 @@ private Alter InstantiateSummarize(SummarizeXml summarizeXml) private Alter InstantiateExtend(ExtendXml extendXml) { - var factory = new ExtensionFactory(ServiceLocator); + var factory = new ExtensionFactory(ServiceLocator, new Context(Variables)); var extender = factory.Instantiate(new ExtendArgs ( extendXml.Identifier diff --git a/NBi.Testing.Core/ResultSet/Alteration/Extension/ExtensionFactoryTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Extension/ExtensionFactoryTest.cs index 53f37418d..9c77ef60d 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Extension/ExtensionFactoryTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Extension/ExtensionFactoryTest.cs @@ -3,6 +3,7 @@ using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; using NBi.Core.Transformation; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -17,7 +18,7 @@ public class ExtensionFactoryTest [Test] public void Instantiate_ExtendArgsNCalc_NCalcExtendEngine() { - var factory = new ExtensionFactory(null); + var factory = new ExtensionFactory(null, new Context(null)); var extender = factory.Instantiate(new ExtendArgs( new ColumnOrdinalIdentifier(1), "a+b*c", @@ -30,7 +31,7 @@ public void Instantiate_ExtendArgsNCalc_NCalcExtendEngine() [Test] public void Instantiate_ExtendArgsNative_NativeExtendEngine() { - var factory = new ExtensionFactory(null); + var factory = new ExtensionFactory(null, new Context(null)); var extender = factory.Instantiate(new ExtendArgs( new ColumnOrdinalIdentifier(1), "[A] | dateTime-to-date | dateTime-to-add(00:15:00, [B])", diff --git a/NBi.Testing.Core/ResultSet/Alteration/Extension/NCalcExtendEngineTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Extension/NCalcExtendEngineTest.cs index 8078c0251..724b1a702 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Extension/NCalcExtendEngineTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Extension/NCalcExtendEngineTest.cs @@ -3,6 +3,7 @@ using NBi.Core.ResultSet.Alteration.Extension; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -25,6 +26,7 @@ public void Execute_StandardRsColumnOrdinal_CorrectExtension() var extender = new NCalcExtendEngine( new ServiceLocator(), + new Context(null), new ColumnOrdinalIdentifier(3), "[#1] * [#2]" ); @@ -48,6 +50,7 @@ public void Execute_StandardRsColumnName_CorrectExtension() var extender = new NCalcExtendEngine( new ServiceLocator(), + new Context(null), new ColumnNameIdentifier("d"), "[b] * [c]" ); @@ -60,6 +63,31 @@ public void Execute_StandardRsColumnName_CorrectExtension() Assert.That(newRs.Rows[2][3], Is.EqualTo(35)); } + [Test] + public void Execute_StandardRsColumnNameAndVariable_CorrectExtension() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "Alpha", 1, 2 }, new object[] { "Beta", 3, 2 }, new object[] { "Gamma", 5, 7 } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + rs.Columns[0].ColumnName = "a"; + rs.Columns[1].ColumnName = "b"; + rs.Columns[2].ColumnName = "c"; + + var extender = new NCalcExtendEngine( + new ServiceLocator(), + new Context(new Dictionary { { "myVar", new GlobalVariable(new LiteralScalarResolver(2)) } }), + new ColumnNameIdentifier("d"), + "[@myVar] * [b] * [c]" + ); + var newRs = extender.Execute(rs); + + Assert.That(newRs.Columns.Count, Is.EqualTo(4)); + Assert.That(newRs.Columns[3].ColumnName, Is.EqualTo("d")); + Assert.That(newRs.Rows[0][3], Is.EqualTo(4)); + Assert.That(newRs.Rows[1][3], Is.EqualTo(12)); + Assert.That(newRs.Rows[2][3], Is.EqualTo(70)); + } + [Test] [TestCase(1000)] [TestCase(10000)] @@ -80,6 +108,7 @@ public void Execute_ManyTimes_Performances(int count) stopWatch.Start(); var extender = new NCalcExtendEngine( new ServiceLocator(), + new Context(null), new ColumnNameIdentifier("c"), "[b] - [a] + Max(a,b) - Sin(a)" ); diff --git a/NBi.Testing.Core/ResultSet/Alteration/Extension/NativeExtendEngineTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Extension/NativeExtendEngineTest.cs index ad2a1469f..6f1c3c9d8 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Extension/NativeExtendEngineTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Extension/NativeExtendEngineTest.cs @@ -3,6 +3,7 @@ using NBi.Core.ResultSet.Alteration.Extension; using NBi.Core.ResultSet.Resolver; using NBi.Core.Scalar.Resolver; +using NBi.Core.Variable; using NUnit.Framework; using System; using System.Collections.Generic; @@ -25,6 +26,7 @@ public void Execute_StandardRsColumnOrdinal_CorrectExtension() var extender = new NativeExtendEngine( new ServiceLocator(), + new Context(null), new ColumnOrdinalIdentifier(3), "#1 | numeric-to-multiply(#2)" ); @@ -48,6 +50,7 @@ public void Execute_StandardRsColumnName_CorrectExtension() var extender = new NativeExtendEngine( new ServiceLocator(), + new Context(null), new ColumnNameIdentifier("d"), "[a] | text-to-first-chars([c]) | text-to-upper" ); @@ -60,6 +63,56 @@ public void Execute_StandardRsColumnName_CorrectExtension() Assert.That(newRs.Rows[2][3], Is.EqualTo("GAMMA")); } + [Test] + public void Execute_StandardRsColumnNameAndVariable_CorrectExtension() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "Alpha", 1, 2 }, new object[] { "Beta", 3, 2 }, new object[] { "Gamma", 5, 7 } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + rs.Columns[0].ColumnName = "a"; + rs.Columns[1].ColumnName = "b"; + rs.Columns[2].ColumnName = "c"; + + var extender = new NativeExtendEngine( + new ServiceLocator(), + new Context(new Dictionary { { "myVar", new GlobalVariable(new LiteralScalarResolver(2)) } }), + new ColumnNameIdentifier("d"), + "[a] | text-to-first-chars(@myVar) | text-to-upper" + ); + var newRs = extender.Execute(rs); + + Assert.That(newRs.Columns.Count, Is.EqualTo(4)); + Assert.That(newRs.Columns[3].ColumnName, Is.EqualTo("d")); + Assert.That(newRs.Rows[0][3], Is.EqualTo("AL")); + Assert.That(newRs.Rows[1][3], Is.EqualTo("BE")); + Assert.That(newRs.Rows[2][3], Is.EqualTo("GA")); + } + + [Test] + public void Execute_StandardRsColumnNameAndVariableFirstArg_CorrectExtension() + { + var args = new ObjectsResultSetResolverArgs(new[] { new object[] { "Alpha", 1, 2 }, new object[] { "Beta", 3, 2 }, new object[] { "Gamma", 5, 7 } }); + var resolver = new ObjectsResultSetResolver(args); + var rs = resolver.Execute(); + rs.Columns[0].ColumnName = "a"; + rs.Columns[1].ColumnName = "b"; + rs.Columns[2].ColumnName = "c"; + + var extender = new NativeExtendEngine( + new ServiceLocator(), + new Context(new Dictionary { { "myVar", new GlobalVariable(new LiteralScalarResolver("foo")) } }), + new ColumnNameIdentifier("d"), + "@myVar | text-to-first-chars(#1) | text-to-upper" + ); + var newRs = extender.Execute(rs); + + Assert.That(newRs.Columns.Count, Is.EqualTo(4)); + Assert.That(newRs.Columns[3].ColumnName, Is.EqualTo("d")); + Assert.That(newRs.Rows[0][3], Is.EqualTo("F")); + Assert.That(newRs.Rows[1][3], Is.EqualTo("FOO")); + Assert.That(newRs.Rows[2][3], Is.EqualTo("FOO")); + } + [Test] [TestCase(1000)] [TestCase(10000)] @@ -80,6 +133,7 @@ public void Execute_ManyTimes_Performances(int count) stopWatch.Start(); var extender = new NativeExtendEngine( new ServiceLocator(), + new Context(null), new ColumnNameIdentifier("c"), "[b] | numeric-to-multiply([a]) | numeric-to-add([a], [b])" ); diff --git a/NBi.Testing.Core/Scalar/Resolver/NCalcScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/NCalcScalarResolverTest.cs index 95177066a..fc0cfb543 100644 --- a/NBi.Testing.Core/Scalar/Resolver/NCalcScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/NCalcScalarResolverTest.cs @@ -18,7 +18,9 @@ public void Instantiate_WithoutRowValues_CorrectComputation() using (var dt = new DataTable()) { var row = dt.NewRow(); - var args = new NCalcScalarResolverArgs("1+1", row); + var context = new Context(null); + var args = new NCalcScalarResolverArgs("1+1", context); + context.Switch(row); var resolver = new NCalcScalarResolver(args); var output = resolver.Execute(); @@ -36,8 +38,10 @@ public void Instantiate_WithRowValuesBasedOnNames_CorrectComputation() dt.Columns.Add("b", typeof(int)); dt.Columns.Add("c", typeof(int)); var row = dt.NewRow(); + var context = new Context(null); row.ItemArray = new object[] { 2, 5, 3 }; - var args = new NCalcScalarResolverArgs("a*Max(b, c)-2", row); + var args = new NCalcScalarResolverArgs("a*Max(b, c)-2", context); + context.Switch(row); var resolver = new NCalcScalarResolver(args); var output = resolver.Execute(); @@ -56,7 +60,9 @@ public void Instantiate_WithRowValuesBasedOnBracketNames_CorrectComputation() dt.Columns.Add("c", typeof(int)); var row = dt.NewRow(); row.ItemArray = new object[] { 2, 5, 3 }; - var args = new NCalcScalarResolverArgs("[a]*Max([b], [c])-2", row); + var context = new Context(null); + var args = new NCalcScalarResolverArgs("[a]*Max([b], [c])-2", context); + context.Switch(row); var resolver = new NCalcScalarResolver(args); var output = resolver.Execute(); @@ -75,7 +81,9 @@ public void Instantiate_WithRowValuesBasedOnOrdinals_CorrectComputation() dt.Columns.Add("c", typeof(int)); var row = dt.NewRow(); row.ItemArray = new object[] { 2, 5, 3 }; - var args = new NCalcScalarResolverArgs("[#0]*Max([#1], [#2])-2", row); + var context = new Context(null); + var args = new NCalcScalarResolverArgs("[#0]*Max([#1], [#2])-2", context); + context.Switch(row); var resolver = new NCalcScalarResolver(args); var output = resolver.Execute(); @@ -84,5 +92,26 @@ public void Instantiate_WithRowValuesBasedOnOrdinals_CorrectComputation() } } + [Test] + public void Instantiate_WithRowValuesBasedOnOrdinalsAndVariable_CorrectComputation() + { + using (var dt = new DataTable()) + { + dt.Columns.Add("a", typeof(int)); + dt.Columns.Add("b", typeof(int)); + dt.Columns.Add("c", typeof(int)); + var row = dt.NewRow(); + row.ItemArray = new object[] { 2, 5, 3 }; + var context = new Context(new Dictionary { { "myVar", new GlobalVariable(new LiteralScalarResolver(10)) } }); + var args = new NCalcScalarResolverArgs("[#0]*Max([#1], [#2])-[@myVar]", context); + context.Switch(row); + var resolver = new NCalcScalarResolver(args); + + var output = resolver.Execute(); + + Assert.That(output, Is.EqualTo(2 * Math.Max(5, 3) - 10)); + } + } + } } diff --git a/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs b/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs index 9c9450405..df0dac01b 100644 --- a/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/ScalarResolverFactoryTest.cs @@ -147,16 +147,13 @@ public void Instantiate_FunctionArgs_FunctionResolver() [Test] public void Instantiate_NCalcArgs_NcalcResolver() { - using (var dt = new DataTable()) - { - var row = dt.NewRow(); - var args = new NCalcScalarResolverArgs("a * b - 2", row); + var context = new Context(null); + var args = new NCalcScalarResolverArgs("a * b - 2", context); - var factory = new ScalarResolverFactory(null); - var resolver = factory.Instantiate(args); + var factory = new ScalarResolverFactory(null); + var resolver = factory.Instantiate(args); - Assert.That(resolver, Is.TypeOf>()); - } + Assert.That(resolver, Is.TypeOf>()); } } } diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 461dc906b..432616803 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -27,9 +27,19 @@ + + + + + + - - + @@ -1060,7 +1070,7 @@ - + \ No newline at end of file From d247bf0797927888ebe9700bf44fdec37a127859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 18:39:49 +0100 Subject: [PATCH 33/57] Fix TextCaster to correctly format a DateTime or a Numeric --- NBi.Core/Scalar/Casting/TextCaster.cs | 10 +++++ .../Resolver/FormatScalarResolverTest.cs | 2 + .../Variable/InstanceFactoryTest.cs | 1 + .../Positive/ResultSetConstraint.nbits | 43 +++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/NBi.Core/Scalar/Casting/TextCaster.cs b/NBi.Core/Scalar/Casting/TextCaster.cs index d4b644e9e..58f9b1909 100644 --- a/NBi.Core/Scalar/Casting/TextCaster.cs +++ b/NBi.Core/Scalar/Casting/TextCaster.cs @@ -12,6 +12,16 @@ public string Execute(object value) { if (value is string) return (string)value; + + if (value is DateTime) + return ((DateTime)value).ToString("yyyy-MM-dd hh:mm:ss"); + + if (value is bool) + return (bool)value ? "True" : "False"; + + var numericCaster = new NumericCaster(); + if (numericCaster.IsStrictlyValid(value)) + return Convert.ToDouble(value).ToString(new CultureFactory().Invariant.NumberFormat); return value.ToString(); } diff --git a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs index 427288e78..43e466077 100644 --- a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs @@ -26,6 +26,7 @@ public void Execute_ExistingNumericVariable_CorrectEvaluation() } [Test] + [Culture("en-us")] public void Execute_VariableWithNativeTransformation_CorrectEvaluation() { var globalVariables = new Dictionary() @@ -40,6 +41,7 @@ public void Execute_VariableWithNativeTransformation_CorrectEvaluation() } [Test] + [Culture("en-us")] public void Execute_VariableWithTwoNativeTransformations_CorrectEvaluation() { var globalVariables = new Dictionary() diff --git a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs index 119995a9f..6f188049e 100644 --- a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs +++ b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs @@ -16,6 +16,7 @@ namespace NBi.Testing.Core.Variable public class InstanceFactoryTest { [Test] + [Culture("en-us")] public void Instantiate_DerivedFromMain_Success() { var resolver = new Mock(); diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 432616803..3ba6de24c 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -1981,6 +1981,49 @@ + + + + + 39.500 + 8.200 + + + + + + + + 2018-10-01 + 8.200 + + + + 0 + + + + + + 2018-10-01 + 39.500 + + + + + + + + + + + + + + + + + From f388cfadef6a8a4922165c785cfbead9c96fc5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 21:07:47 +0100 Subject: [PATCH 34/57] Fix TextCaster --- NBi.Core/Scalar/Casting/TextCaster.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NBi.Core/Scalar/Casting/TextCaster.cs b/NBi.Core/Scalar/Casting/TextCaster.cs index 58f9b1909..0bcc49506 100644 --- a/NBi.Core/Scalar/Casting/TextCaster.cs +++ b/NBi.Core/Scalar/Casting/TextCaster.cs @@ -14,14 +14,14 @@ public string Execute(object value) return (string)value; if (value is DateTime) - return ((DateTime)value).ToString("yyyy-MM-dd hh:mm:ss"); + return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"); if (value is bool) return (bool)value ? "True" : "False"; var numericCaster = new NumericCaster(); if (numericCaster.IsStrictlyValid(value)) - return Convert.ToDouble(value).ToString(new CultureFactory().Invariant.NumberFormat); + return Convert.ToDecimal(value).ToString(new CultureFactory().Invariant.NumberFormat); return value.ToString(); } From 5e597a39ffa708e307190893c90a19df7df1134a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 17 Dec 2019 21:57:08 +0100 Subject: [PATCH 35/57] Add an untyped type and the cells' values should always be an object and not a string --- NBi.Core/NBi.Core.csproj | 1 + .../Alteration/Lookup/LookupReplaceEngine.cs | 2 +- NBi.Core/ResultSet/ColumnType.cs | 1 + NBi.Core/ResultSet/ICell.cs | 2 +- .../ResultSet/Resolver/ObjectsToRowsHelper.cs | 4 +- NBi.Core/Scalar/Casting/CasterFactory.cs | 1 + NBi.Core/Scalar/Casting/UntypedCaster.cs | 18 +++++++++ .../Calculation/Ranking/BottomRankingTest.cs | 16 ++++---- .../Calculation/Ranking/TopRankingTest.cs | 17 +++++---- .../Lookup/LookupReplaceEngineTest.cs | 37 +++++++++++++++++++ NBi.Testing.Core/ResultSet/ResultSetTest.cs | 16 ++++---- NBi.Xml/Items/ResultSet/CellXml.cs | 10 ++--- 12 files changed, 93 insertions(+), 32 deletions(-) create mode 100644 NBi.Core/Scalar/Casting/UntypedCaster.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 1ef09debb..7ebe4992b 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -552,6 +552,7 @@ + diff --git a/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs b/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs index 1720899a5..a934d112c 100644 --- a/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs +++ b/NBi.Core/ResultSet/Alteration/Lookup/LookupReplaceEngine.cs @@ -25,7 +25,7 @@ public ResultSet Execute(ResultSet candidate) var stopWatch = new Stopwatch(); stopWatch.Start(); var referenceKeyRetriever = BuildColumnsRetriever(Args.Mapping, x => x.ReferenceColumn); - var referenceValueRetriever = BuildColumnsRetriever(new ColumnMapping(Args.Replacement, ColumnType.Text), x => x.ReferenceColumn); + var referenceValueRetriever = BuildColumnsRetriever(new ColumnMapping(Args.Replacement, ColumnType.Untyped), x => x.ReferenceColumn); var index = BuildReferenceIndex(reference.Table, referenceKeyRetriever, referenceValueRetriever); Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceInfo, $"Built the index for reference table containing {index.Count()} rows [{stopWatch.Elapsed:d'.'hh':'mm':'ss'.'fff'ms'}]"); diff --git a/NBi.Core/ResultSet/ColumnType.cs b/NBi.Core/ResultSet/ColumnType.cs index e6092b772..678b00b23 100644 --- a/NBi.Core/ResultSet/ColumnType.cs +++ b/NBi.Core/ResultSet/ColumnType.cs @@ -4,6 +4,7 @@ namespace NBi.Core.ResultSet { public enum ColumnType { + Untyped = -1, [XmlEnum(Name = "text")] Text = 0, [XmlEnum(Name = "numeric")] diff --git a/NBi.Core/ResultSet/ICell.cs b/NBi.Core/ResultSet/ICell.cs index 33db7f7c7..adbd7873c 100644 --- a/NBi.Core/ResultSet/ICell.cs +++ b/NBi.Core/ResultSet/ICell.cs @@ -7,7 +7,7 @@ namespace NBi.Core.ResultSet { public interface ICell { - string Value { get; set; } + object Value { get; set; } string ColumnName { get; set; } } } diff --git a/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs b/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs index 53add00ec..208efc223 100644 --- a/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs +++ b/NBi.Core/ResultSet/Resolver/ObjectsToRowsHelper.cs @@ -17,7 +17,7 @@ public IEnumerable Execute(IEnumerable objects) if (obj is IEnumerable items) foreach (var item in items) { - var cell = new Cell() { Value = item?.ToString() }; + var cell = new Cell() { Value = item }; row.Cells.Add(cell); } rows.Add(row); @@ -35,7 +35,7 @@ private class Row : IRow private class Cell : ICell { - public string Value { get; set; } + public object Value { get; set; } public string ColumnName { get; set; } } } diff --git a/NBi.Core/Scalar/Casting/CasterFactory.cs b/NBi.Core/Scalar/Casting/CasterFactory.cs index 30a45c3bb..dc8352dc6 100644 --- a/NBi.Core/Scalar/Casting/CasterFactory.cs +++ b/NBi.Core/Scalar/Casting/CasterFactory.cs @@ -29,6 +29,7 @@ public ICaster Instantiate(ColumnType type) { switch (type) { + case ColumnType.Untyped: return new UntypedCaster(); case ColumnType.Text: return new TextCaster(); case ColumnType.Numeric: return new NumericCaster(); case ColumnType.Boolean: return new BooleanCaster(); diff --git a/NBi.Core/Scalar/Casting/UntypedCaster.cs b/NBi.Core/Scalar/Casting/UntypedCaster.cs new file mode 100644 index 000000000..448f0048d --- /dev/null +++ b/NBi.Core/Scalar/Casting/UntypedCaster.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Scalar.Casting +{ + class UntypedCaster : ICaster + { + public object Execute(object value) + => value; + + object ICaster.Execute(object value) => Execute(value); + + public bool IsValid(object value) => true; + } +} diff --git a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs index b3fef70ab..92e806396 100644 --- a/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/BottomRankingTest.cs @@ -34,7 +34,7 @@ public void Apply_Rows_Success(object[] values, ColumnType columnType, int index var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); } @@ -55,9 +55,9 @@ public void Apply_TopTwo_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(2)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Min(), 1)).Min())); } @@ -76,11 +76,11 @@ public void Apply_Larger_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(values.Count())); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Min(), 1)).Min())); - Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2].ToString())); + Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2])); Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[1], Is.EqualTo(values.Max())); } @@ -101,7 +101,7 @@ public void Apply_Alias_Success(object[] values, ColumnType columnType, int inde var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Min())); } @@ -123,7 +123,7 @@ public void Apply_Exp_Success(object[] values, ColumnType columnType, int index) var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo("125")); } diff --git a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs index 7fbb6ba00..c1ae1dbe7 100644 --- a/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs +++ b/NBi.Testing.Core/Calculation/Ranking/TopRankingTest.cs @@ -21,6 +21,7 @@ public class TopRankingTest [TestCase(new object[] { "100", "120", "110", "130", "105" }, ColumnType.Numeric, 4)] [TestCase(new object[] { "a", "b", "e", "c", "d" }, ColumnType.Text, 3)] [TestCase(new object[] { "2010-02-02 07:12:16.52", "2010-02-02 07:12:16.55", "2010-02-02 08:12:16.50" }, ColumnType.DateTime, 3)] + public void Apply_Rows_Success(object[] values, ColumnType columnType, int index) { var i = 0; @@ -34,7 +35,7 @@ public void Apply_Rows_Success(object[] values, ColumnType columnType, int index var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); } @@ -55,9 +56,9 @@ public void Apply_TopTwo_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(2)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Max(), 1)).Max())); } @@ -76,11 +77,11 @@ public void Apply_Larger_Success(object[] values, ColumnType columnType, int[] i var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(values.Count())); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0].ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index[0])); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); - Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1].ToString())); + Assert.That(filteredRs.Rows[1].ItemArray[0], Is.EqualTo(index[1])); Assert.That(filteredRs.Rows[1].ItemArray[1], Is.EqualTo(values.Except(Enumerable.Repeat(values.Max(), 1)).Max())); - Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2].ToString())); + Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[0], Is.EqualTo(index[2])); Assert.That(filteredRs.Rows[values.Count() - 1].ItemArray[1], Is.EqualTo(values.Min())); } @@ -102,7 +103,7 @@ public void Apply_Alias_Success(object[] values, ColumnType columnType, int inde var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo(values.Max())); } @@ -124,7 +125,7 @@ public void Apply_Exp_Success(object[] values, ColumnType columnType, int index) var filteredRs = ranking.Apply(rs); Assert.That(filteredRs.Rows.Count, Is.EqualTo(1)); - Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index.ToString())); + Assert.That(filteredRs.Rows[0].ItemArray[0], Is.EqualTo(index)); Assert.That(filteredRs.Rows[0].ItemArray[1], Is.EqualTo("139")); } diff --git a/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs index fe7e3b7bb..3462220c8 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Lookup/LookupReplaceEngineTest.cs @@ -54,6 +54,43 @@ public void Execute_AllLookupFound_CorrectReplacement() Assert.That(result.Rows.Cast().Select(x => x[1] as string).Where(x => x != "alpha" && x != "beta"), Is.Empty); } + [Test] + public void Execute_AllLookupFoundSwitchingFromTextToNumeric_CorrectReplacement() + { + var candidate = new ObjectsResultSetResolver( + new ObjectsResultSetResolverArgs( + new[] { + new object[] { 1, "A", 100 }, + new object[] { 2, "B", 101 }, + new object[] { 3, "A", 125 }, + new object[] { 4, "B", 155 } + } + )).Execute(); + + var reference = new ResultSetService( + new ObjectsResultSetResolver( + new ObjectsResultSetResolverArgs( + new[] { + new object[] { "A", 10.2 }, + new object[] { "B", 21.1 }, + } + )).Execute, null); + + var engine = new LookupReplaceEngine( + new LookupReplaceArgs( + reference, + new ColumnMapping(new ColumnOrdinalIdentifier(1), new ColumnOrdinalIdentifier(0), ColumnType.Text), + new ColumnOrdinalIdentifier(1) + )); + + var result = engine.Execute(candidate); + Assert.That(result.Columns.Count, Is.EqualTo(3)); + Assert.That(result.Rows.Count, Is.EqualTo(4)); + Assert.That(result.Rows.Cast().Select(x => x[1]).Distinct(), Does.Contain(10.2)); + Assert.That(result.Rows.Cast().Select(x => x[1]).Distinct(), Does.Contain(21.1)); + Assert.That(result.Rows.Cast().Select(x => Convert.ToDecimal(x[1])).Where(x => x != 10.2m && x != 21.1m), Is.Empty); + } + [Test] public void ExecuteWithFailureStretegy_OneLookupMissing_ExceptionThrown() { diff --git a/NBi.Testing.Core/ResultSet/ResultSetTest.cs b/NBi.Testing.Core/ResultSet/ResultSetTest.cs index a66c654cf..0cd2d1d37 100644 --- a/NBi.Testing.Core/ResultSet/ResultSetTest.cs +++ b/NBi.Testing.Core/ResultSet/ResultSetTest.cs @@ -62,20 +62,20 @@ public void Load_ThreeIRowsWithTwoICells_ThreeRowsAndTwoColumns() var objects = new List { Mock.Of ( x => x.Cells == new List { - Mock.Of( y=> y.Value == "CY 2001"), - Mock.Of( y=> y.Value == "1000") } + Mock.Of(y => (string)(y.Value) == "CY 2001"), + Mock.Of(y => (decimal)(y.Value) == 1000) } ) , Mock.Of( x => x.Cells == new List { - Mock.Of(y=> y.Value == "CY 2002"), - Mock.Of(y => y.Value == "10.4") } + Mock.Of(y => (string)(y.Value) == "CY 2002"), + Mock.Of(y => (decimal)(y.Value) == 10.4m) } ) , Mock.Of( x => x.Cells == new List { - Mock.Of ( y=> y.Value == "CY 2003"), - Mock.Of(y => y.Value == "200") } + Mock.Of(y => (string)(y.Value) == "CY 2003"), + Mock.Of(y => (decimal)(y.Value) == 200) } ) }; @@ -86,7 +86,9 @@ public void Load_ThreeIRowsWithTwoICells_ThreeRowsAndTwoColumns() Assert.That(rs.Rows.Count, Is.EqualTo(3)); Assert.That(rs.Rows[0].ItemArray[0], Is.EqualTo("CY 2001")); - Assert.That(rs.Rows[0].ItemArray[1], Is.EqualTo("1000")); + Assert.That(rs.Rows[0].ItemArray[1], Is.EqualTo(1000)); + Assert.That(rs.Rows[1].ItemArray[0], Is.EqualTo("CY 2002")); + Assert.That(rs.Rows[1].ItemArray[1], Is.EqualTo(10.4)); } [Test] diff --git a/NBi.Xml/Items/ResultSet/CellXml.cs b/NBi.Xml/Items/ResultSet/CellXml.cs index 7cf05d6dc..732180550 100644 --- a/NBi.Xml/Items/ResultSet/CellXml.cs +++ b/NBi.Xml/Items/ResultSet/CellXml.cs @@ -6,14 +6,14 @@ namespace NBi.Xml.Items.ResultSet public class CellXml : ICell { [XmlText] - public string Value { get; set; } + public string StringValue { get; set; } + + [XmlIgnore] + public object Value { get => StringValue; set { StringValue = value.ToString(); } } [XmlAttribute("column-name")] public string ColumnName { get; set; } - public override string ToString() - { - return Value; - } + public override string ToString() => StringValue.ToString(); } } From 12e4d964929701448b7d1ed081a54de236c7275d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 15:15:13 +0100 Subject: [PATCH 36/57] Add test to assert that file is already supporting variables --- .../Positive/ResultSetConstraint.nbits | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 432616803..70f3edfdd 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -37,6 +37,9 @@ 1+1 + + + @@ -604,6 +607,46 @@ + + + + + ~..\Csv\{@csvFileName}.xml + + //PurchaseOrder/Items/Item + + + + + + + + + + + 99503 + 872-AA + + + 99503 + 926-AA + + + 99505 + 456-NM + + + 99504 + 898-AZ + + + 99504 + 898-AM + + + + + From 9fa5cb50fed1af36ac2ce22d6953575512aa75ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 15:36:21 +0100 Subject: [PATCH 37/57] Fix culture for a few tests --- NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs | 2 ++ NBi.Testing.Core/Variable/InstanceFactoryTest.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs index 427288e78..5b9840299 100644 --- a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs @@ -26,6 +26,7 @@ public void Execute_ExistingNumericVariable_CorrectEvaluation() } [Test] + [SetCulture("en-us")] public void Execute_VariableWithNativeTransformation_CorrectEvaluation() { var globalVariables = new Dictionary() @@ -40,6 +41,7 @@ public void Execute_VariableWithNativeTransformation_CorrectEvaluation() } [Test] + [SetCulture("en-us")] public void Execute_VariableWithTwoNativeTransformations_CorrectEvaluation() { var globalVariables = new Dictionary() diff --git a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs index 119995a9f..1de2573b4 100644 --- a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs +++ b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs @@ -16,6 +16,7 @@ namespace NBi.Testing.Core.Variable public class InstanceFactoryTest { [Test] + [SetCulture("en-us")] public void Instantiate_DerivedFromMain_Success() { var resolver = new Mock(); From 4ddac4e72719e5825e32e36d9684ec2849160506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 15:36:38 +0100 Subject: [PATCH 38/57] Remap to the new package for StringTemplate --- NBi.Core/NBi.Core.csproj | 6 +++--- NBi.Core/packages.config | 3 ++- NBi.UI.Genbi/NBi.UI.Genbi.csproj | 7 +++++-- NBi.UI.Genbi/packages.config | 3 ++- NBi.genbiL/NBi.genbiL.csproj | 7 +++++-- NBi.genbiL/packages.config | 3 ++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 1ef09debb..5b0cb0a23 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -46,10 +46,10 @@ - ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll + ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll - - ..\packages\Antlr4.StringTemplate.4.0.6.9004\lib\net35\Antlr4.StringTemplate.dll + + ..\packages\StringTemplate4.4.0.8\lib\net35-client\Antlr4.StringTemplate.dll ..\packages\Deedle.2.0.4\lib\net45\Deedle.dll diff --git a/NBi.Core/packages.config b/NBi.Core/packages.config index 2598af1d9..45f98ba94 100644 --- a/NBi.Core/packages.config +++ b/NBi.Core/packages.config @@ -1,7 +1,7 @@  - + @@ -13,6 +13,7 @@ + diff --git a/NBi.UI.Genbi/NBi.UI.Genbi.csproj b/NBi.UI.Genbi/NBi.UI.Genbi.csproj index 2d6a24e2b..6dda82521 100644 --- a/NBi.UI.Genbi/NBi.UI.Genbi.csproj +++ b/NBi.UI.Genbi/NBi.UI.Genbi.csproj @@ -55,8 +55,11 @@ favicon.ico - - ..\packages\Antlr4.StringTemplate.4.0.6.9004\lib\net35\Antlr4.StringTemplate.dll + + ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\packages\StringTemplate4.4.0.8\lib\net35-client\Antlr4.StringTemplate.dll ..\packages\ICSharpCode.TextEditor.3.2.1.6466\lib\Net20\ICSharpCode.TextEditor.dll diff --git a/NBi.UI.Genbi/packages.config b/NBi.UI.Genbi/packages.config index f5f1be3c1..0e9e0bc2c 100644 --- a/NBi.UI.Genbi/packages.config +++ b/NBi.UI.Genbi/packages.config @@ -1,6 +1,7 @@  - + + \ No newline at end of file diff --git a/NBi.genbiL/NBi.genbiL.csproj b/NBi.genbiL/NBi.genbiL.csproj index 8c3378232..86e9aeb76 100644 --- a/NBi.genbiL/NBi.genbiL.csproj +++ b/NBi.genbiL/NBi.genbiL.csproj @@ -34,8 +34,11 @@ false - - ..\packages\Antlr4.StringTemplate.4.0.6.9004\lib\net35\Antlr4.StringTemplate.dll + + ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\packages\StringTemplate4.4.0.8\lib\net35-client\Antlr4.StringTemplate.dll ..\packages\PocketCsvReader.1.0.0\lib\net461\PocketCsvReader.dll diff --git a/NBi.genbiL/packages.config b/NBi.genbiL/packages.config index 16c08f030..855c5ced9 100644 --- a/NBi.genbiL/packages.config +++ b/NBi.genbiL/packages.config @@ -1,7 +1,8 @@  - + + \ No newline at end of file From a31f5fb92ae13a45657698a57cbcae6fe8f484d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 15:55:33 +0100 Subject: [PATCH 39/57] Remove cultures after double-check of behaviour --- .../Resolver/FormatScalarResolverTest.cs | 20 ++++++++++++++++--- .../Variable/InstanceFactoryTest.cs | 3 +-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs index 5b9840299..9181d59d8 100644 --- a/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs +++ b/NBi.Testing.Core/Scalar/Resolver/FormatScalarResolverTest.cs @@ -37,11 +37,25 @@ public void Execute_VariableWithNativeTransformation_CorrectEvaluation() var resolver = new FormatScalarResolver(args, new ServiceLocator()); var text = resolver.Execute(); Console.WriteLine(text); - Assert.That(text, Is.EqualTo($"First of May was a {new DateTime(2019, 5, 1):dddd}")); + Assert.That(text, Is.EqualTo($"First of May was a Wednesday")); + } + + [Test] + [SetCulture("fr-fr")] + public void Execute_VariableWithNativeTransformation_IndependantOfLocalCulture() + { + var globalVariables = new Dictionary() + { + { "myVar" , new GlobalVariable(new CSharpScalarResolver( new CSharpScalarResolverArgs("new DateTime(2019, 6, 1)"))) }, + }; + var args = new FormatScalarResolverArgs("First of May was a {@myVar | dateTime-to-previous-month:dddd}", globalVariables); + var resolver = new FormatScalarResolver(args, new ServiceLocator()); + var text = resolver.Execute(); + Console.WriteLine(text); + Assert.That(text, Is.EqualTo($"First of May was a Wednesday")); } [Test] - [SetCulture("en-us")] public void Execute_VariableWithTwoNativeTransformations_CorrectEvaluation() { var globalVariables = new Dictionary() @@ -52,7 +66,7 @@ public void Execute_VariableWithTwoNativeTransformations_CorrectEvaluation() var resolver = new FormatScalarResolver(args, new ServiceLocator()); var text = resolver.Execute(); Console.WriteLine(text); - Assert.That(text, Is.EqualTo($"First day of the month before was a {new DateTime(2019, 5, 1):dddd}")); + Assert.That(text, Is.EqualTo($"First day of the month before was a Wednesday")); } [Test] diff --git a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs index 1de2573b4..9a943a816 100644 --- a/NBi.Testing.Core/Variable/InstanceFactoryTest.cs +++ b/NBi.Testing.Core/Variable/InstanceFactoryTest.cs @@ -16,7 +16,6 @@ namespace NBi.Testing.Core.Variable public class InstanceFactoryTest { [Test] - [SetCulture("en-us")] public void Instantiate_DerivedFromMain_Success() { var resolver = new Mock(); @@ -28,7 +27,7 @@ public void Instantiate_DerivedFromMain_Success() var secondTransformation = new NativeTransformer(new ServiceLocator(), null);; secondTransformation.Initialize("text-to-last-chars(8) | text-to-dateTime(yyyyMMdd)"); - var thirdTransformation = new NativeTransformer(new ServiceLocator(), null);; + var thirdTransformation = new NativeTransformer(new ServiceLocator(), null);; thirdTransformation.Initialize("dateTime-to-add(7)"); var args = new DerivedVariableInstanceArgs() From fd519305d1298f064e982a65d9083ea33916e340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 16:13:52 +0100 Subject: [PATCH 40/57] Update Readme.md Updated "still maintained" badge --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index c2c0bb9d9..c7f620c9d 100644 --- a/Readme.md +++ b/Readme.md @@ -16,7 +16,7 @@ The main goal of this framework is to let users create tests with a declarative [![nuget](https://img.shields.io/nuget/vpre/NBi.Framework.svg?color=%23427682&label=Beta)](https://www.nuget.org/packages/NBi.Framework/) **Dev. activity:** [![GitHub last commit](https://img.shields.io/github/last-commit/Seddryck/nbi.svg)](https://github.com/Seddryck/NBi/releases/latest) -![Still maintained](https://img.shields.io/maintenance/yes/2019.svg) +![Still maintained](https://img.shields.io/maintenance/yes/2020.svg) ![GitHub commits since tagged version](https://img.shields.io/github/commits-since/Seddryck/NBi/v1.21/develop) ![GitHub commits on v2.0](https://img.shields.io/github/commits-since/seddryck/nbi/v1.21/develop_v2?label=commits%20on%20v2.0) ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/Seddryck/NBi) From eb8ca9ac99aff7ab33b4fa6bb9d3f32a7c265291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 3 Jan 2020 23:59:49 +0100 Subject: [PATCH 41/57] Add the explicit references to files in lib and tools --- .packages/NBi.Extensibility/NBi.Extensibility.nuspec | 4 ++++ .packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec | 1 + .packages/NBi.Framework/NBi.Framework.nuspec | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec index 98944143f..74149f935 100644 --- a/.packages/NBi.Extensibility/NBi.Extensibility.nuspec +++ b/.packages/NBi.Extensibility/NBi.Extensibility.nuspec @@ -16,8 +16,12 @@ Copyright 2013-$thisYear$ Test NBi SQL SSAS SSIS SSRS + + + + \ No newline at end of file diff --git a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec index 5aa7e07dd..5177c2318 100644 --- a/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec +++ b/.packages/NBi.Framework.Tools/NBi.Framework.Tools.nuspec @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/.packages/NBi.Framework/NBi.Framework.nuspec b/.packages/NBi.Framework/NBi.Framework.nuspec index fe4bbc056..dc2230413 100644 --- a/.packages/NBi.Framework/NBi.Framework.nuspec +++ b/.packages/NBi.Framework/NBi.Framework.nuspec @@ -17,10 +17,13 @@ Test NBi SQL SSAS SSIS SSRS - $depList$ + + $depList$ + + \ No newline at end of file From dc8a9e114b2b324f1d9ee2b98f6d91c1602809a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 5 Jan 2020 19:06:31 +0100 Subject: [PATCH 42/57] Implement and test the two new conditions --- .../IO/Conditions/FileExistsCondition.cs | 41 ++++++++++ .../FolderExistsCondition.cs | 6 +- .../Decoration/IO/FileExistsConditionArgs.cs | 19 +++++ NBi.Core/NBi.Core.csproj | 4 +- .../IO/Conditions/FileExistsConditionTest.cs | 76 ++++++++++++++++++ .../Conditions/FolderExistsConditionTest.cs | 77 +++++++++++++++++++ NBi.Testing/NBi.Testing.csproj | 2 + 7 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs rename NBi.Core/Decoration/IO/{Commands => Conditions}/FolderExistsCondition.cs (88%) create mode 100644 NBi.Core/Decoration/IO/FileExistsConditionArgs.cs create mode 100644 NBi.Testing/Integration/Core/Decoration/IO/Conditions/FileExistsConditionTest.cs create mode 100644 NBi.Testing/Integration/Core/Decoration/IO/Conditions/FolderExistsConditionTest.cs diff --git a/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs b/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs new file mode 100644 index 000000000..a28097d46 --- /dev/null +++ b/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using NBi.Core.Decoration.IO; +using System.Diagnostics; +using NBi.Extensibility; + +namespace NBi.Core.Decoration.IO.Conditions +{ + class FileExistsCondition : IDecorationCondition + { + private FileExistsConditionArgs Args { get; } + + public string Message => throw new NotImplementedException(); + + public FileExistsCondition(FileExistsConditionArgs args) => Args = args; + + public bool Validate() + { + var fullPath = PathExtensions.CombineOrRoot(Args.BasePath, Args.FolderName.Execute(), Args.FileName.Execute()); + + var conditions = new List>() { ExistsCondition }; + if (Args.NotEmpty.Execute()) + conditions.Add(IsNotEmptyCondition); + + var result = true; + var enumerator = conditions.GetEnumerator(); + while (result && enumerator.MoveNext()) + result = enumerator.Current.Invoke(fullPath); + return result; + } + + protected bool ExistsCondition(string fullPath) + => File.Exists(fullPath); + + protected bool IsNotEmptyCondition(string fullPath) + => new FileInfo(fullPath).Length > 0; + } +} diff --git a/NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs b/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs similarity index 88% rename from NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs rename to NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs index aae492559..bc96392c4 100644 --- a/NBi.Core/Decoration/IO/Commands/FolderExistsCondition.cs +++ b/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs @@ -7,7 +7,7 @@ using System.Diagnostics; using NBi.Extensibility; -namespace NBi.Core.Decoration.IO.Commands +namespace NBi.Core.Decoration.IO.Conditions { class FolderExistsCondition : IDecorationCondition { @@ -24,7 +24,7 @@ public bool Validate() var conditions = new List>() { ExistsCondition }; if (Args.NotEmpty.Execute()) - conditions.Add(IsEmptyCondition); + conditions.Add(IsNotEmptyCondition); var result = true; var enumerator = conditions.GetEnumerator(); @@ -36,7 +36,7 @@ public bool Validate() protected bool ExistsCondition(string fullPath) => Directory.Exists(fullPath); - protected bool IsEmptyCondition(string fullPath) + protected bool IsNotEmptyCondition(string fullPath) => !string.IsNullOrEmpty(Directory.EnumerateFiles(fullPath).FirstOrDefault()); } } diff --git a/NBi.Core/Decoration/IO/FileExistsConditionArgs.cs b/NBi.Core/Decoration/IO/FileExistsConditionArgs.cs new file mode 100644 index 000000000..cca169c58 --- /dev/null +++ b/NBi.Core/Decoration/IO/FileExistsConditionArgs.cs @@ -0,0 +1,19 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NBi.Core.Decoration.IO +{ + public class FileExistsConditionArgs : IIoConditionArgs + { + public string BasePath { get; } + public IScalarResolver FolderName { get; } + public IScalarResolver FileName { get; } + public IScalarResolver NotEmpty { get; } + + public FileExistsConditionArgs(string basePath, IScalarResolver folderName, IScalarResolver fileName, IScalarResolver notEmpty) + => (BasePath, FolderName, FileName, NotEmpty) = (basePath, folderName, fileName, notEmpty); + } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 1ef09debb..d12250df6 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -149,7 +149,9 @@ - + + + diff --git a/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FileExistsConditionTest.cs b/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FileExistsConditionTest.cs new file mode 100644 index 000000000..3b5b20b52 --- /dev/null +++ b/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FileExistsConditionTest.cs @@ -0,0 +1,76 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using NBi.Core.Decoration.IO; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Decoration.IO.Conditions; + +namespace NBi.Testing.Integration.Core.Decoration.IO.Conditions +{ + public class FileExistsConditionTest + { + [SetUp] + public void CreateDirectory() + { + if (!Directory.Exists("Temp")) + Directory.CreateDirectory("Temp"); + + if(!Directory.Exists(@"Temp\Target")) + Directory.CreateDirectory(@"Temp\Target"); + + File.WriteAllText(@"Temp\Target\myFile.txt", "a little text"); + File.WriteAllText(@"Temp\Target\myEmptyFile.txt", string.Empty); + } + + [Test] + public void Execute_ExistingFile_True() + { + var fileArgs = new FileExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"Target\"), + new LiteralScalarResolver(@"myFile.txt"), + new LiteralScalarResolver(false) + ); + + var condition = new FileExistsCondition(fileArgs); + Assert.That(condition.Validate(), Is.True); + } + + [Test] + public void Execute_ExistingFileButEmpty_True() + { + var fileArgs = new FileExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"Target"), + new LiteralScalarResolver(@"myEmptyFile.txt"), + new LiteralScalarResolver(true) + ); + + var condition = new FileExistsCondition(fileArgs); + Assert.That(condition.Validate(), Is.False); + } + + [Test] + public void Execute_ExistingFileButNotEmpty_True() + { + + var fileArgs = new FileExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"Target"), + new LiteralScalarResolver(@"myFile.txt"), + new LiteralScalarResolver(true) + ); + + var condition = new FileExistsCondition(fileArgs); + Assert.That(condition.Validate(), Is.True); + } + + } +} diff --git a/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FolderExistsConditionTest.cs b/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FolderExistsConditionTest.cs new file mode 100644 index 000000000..c448533a5 --- /dev/null +++ b/NBi.Testing/Integration/Core/Decoration/IO/Conditions/FolderExistsConditionTest.cs @@ -0,0 +1,77 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using NBi.Core.Decoration.IO; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Decoration.IO.Conditions; + +namespace NBi.Testing.Integration.Core.Decoration.IO.Conditions +{ + public class FolderExistsConditionTest + { + [SetUp] + public void CreateDirectory() + { + if (!Directory.Exists("Temp")) + Directory.CreateDirectory("Temp"); + + if(Directory.Exists(@"Temp\Target")) + Directory.Delete(@"Temp\Target", true); + Directory.CreateDirectory(@"Temp\Target"); + + if (Directory.Exists(@"Temp\TargetNotExisting")) + Directory.Delete(@"Temp\TargetNotExisting", true); + } + + [Test] + public void Execute_ExistingFolder_True() + { + var folderArgs = new FolderExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"."), + new LiteralScalarResolver(@"Target"), + new LiteralScalarResolver(false) + ); + + var condition = new FolderExistsCondition(folderArgs); + Assert.That(condition.Validate(), Is.True); + } + + [Test] + public void Execute_ExistingFolderButEmpty_True() + { + var folderArgs = new FolderExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"."), + new LiteralScalarResolver(@"Target"), + new LiteralScalarResolver(true) + ); + + var condition = new FolderExistsCondition(folderArgs); + Assert.That(condition.Validate(), Is.False); + } + + [Test] + public void Execute_ExistingFolderButNotEmpty_True() + { + File.WriteAllText(@"Temp\Target\file.txt", "a little text"); + var folderArgs = new FolderExistsConditionArgs + ( + @"Temp\", + new LiteralScalarResolver(@"."), + new LiteralScalarResolver(@"Target"), + new LiteralScalarResolver(true) + ); + + var condition = new FolderExistsCondition(folderArgs); + Assert.That(condition.Validate(), Is.True); + } + + } +} diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 75d51231f..383885638 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -150,6 +150,8 @@ + + From fd13bee6f793da52049837cf0e4e5c5028ebe64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Sun, 5 Jan 2020 19:33:33 +0100 Subject: [PATCH 43/57] Serialization of file-exists and folder-exists --- NBi.NUnit/Builder/Helper/ConditionHelper.cs | 4 +- .../Decoration/ConditionXmlTest.cs | 90 ++++++++++++++++++- .../Resources/ConditionXmlTestSuite.xml | 46 ++++++++-- .../Condition/FileExistsConditionXml.cs | 20 +++++ .../Condition/FolderExistsConditionXml.cs | 20 +++++ ...ngXml.cs => ServiceRunningConditionXml.cs} | 44 ++++----- NBi.Xml/Decoration/ConditionXml.cs | 6 +- NBi.Xml/NBi.Xml.csproj | 4 +- NBi.Xml/Schema/BaseType.xsd | 12 +++ 9 files changed, 207 insertions(+), 39 deletions(-) create mode 100644 NBi.Xml/Decoration/Condition/FileExistsConditionXml.cs create mode 100644 NBi.Xml/Decoration/Condition/FolderExistsConditionXml.cs rename NBi.Xml/Decoration/Condition/{ServiceRunningXml.cs => ServiceRunningConditionXml.cs} (77%) diff --git a/NBi.NUnit/Builder/Helper/ConditionHelper.cs b/NBi.NUnit/Builder/Helper/ConditionHelper.cs index 95ae17a6b..a9f2c4842 100644 --- a/NBi.NUnit/Builder/Helper/ConditionHelper.cs +++ b/NBi.NUnit/Builder/Helper/ConditionHelper.cs @@ -31,7 +31,7 @@ public IDecorationConditionArgs Execute(object condition) switch (condition) { case CustomConditionXml custom: return BuildCustomCondition(custom); - case ServiceRunningXml serviceRunning: return BuildServiceRunning(serviceRunning); + case ServiceRunningConditionXml serviceRunning: return BuildServiceRunning(serviceRunning); default: throw new ArgumentOutOfRangeException(); } } @@ -47,7 +47,7 @@ private IDecorationConditionArgs BuildCustomCondition(CustomConditionXml custom) ); } - private IDecorationConditionArgs BuildServiceRunning(ServiceRunningXml serviceRunning) + private IDecorationConditionArgs BuildServiceRunning(ServiceRunningConditionXml serviceRunning) { var scalarHelper = new ScalarHelper(serviceLocator, new Context(variables)); return new RunningArgs( diff --git a/NBi.Testing.Xml/Decoration/ConditionXmlTest.cs b/NBi.Testing.Xml/Decoration/ConditionXmlTest.cs index bc418b1e2..0ea140fd2 100644 --- a/NBi.Testing.Xml/Decoration/ConditionXmlTest.cs +++ b/NBi.Testing.Xml/Decoration/ConditionXmlTest.cs @@ -47,14 +47,14 @@ public void Deserialize_SampleFile_RunningService() TestSuiteXml ts = DeserializeSample(); // Check the properties of the object. - Assert.That(ts.Tests[testNr].Condition.Predicates[0], Is.TypeOf()); - var check = ts.Tests[testNr].Condition.Predicates[0] as ServiceRunningXml; + Assert.That(ts.Tests[testNr].Condition.Predicates[0], Is.TypeOf()); + var check = ts.Tests[testNr].Condition.Predicates[0] as ServiceRunningConditionXml; Assert.That(check.TimeOut, Is.EqualTo("5000")); //Default value Assert.That(check.ServiceName, Is.EqualTo("MyService")); // Check the properties of the object. - Assert.That(ts.Tests[testNr].Condition.Predicates[1], Is.TypeOf()); - var check2 = ts.Tests[testNr].Condition.Predicates[1] as ServiceRunningXml; + Assert.That(ts.Tests[testNr].Condition.Predicates[1], Is.TypeOf()); + var check2 = ts.Tests[testNr].Condition.Predicates[1] as ServiceRunningConditionXml; Assert.That(check2.TimeOut, Is.EqualTo("1000")); //Value Specified Assert.That(check2.ServiceName, Is.EqualTo("MyService2")); } @@ -127,5 +127,87 @@ public void Serialize_CustomWithParameters_Correct() Console.WriteLine(xml); Assert.That(xml, Does.Contain("myValue")); } + + [Test] + public void Deserialize_SampleFile_FolderExists() + { + int testNr = 2; + + // Create an instance of the XmlSerializer specifying type and namespace. + var ts = DeserializeSample(); + + // Check the properties of the object. + Assert.That(ts.Tests[testNr].Condition.Predicates[0], Is.TypeOf()); + var condition = ts.Tests[testNr].Condition.Predicates[0] as FolderExistsConditionXml; + Assert.That(condition.Path, Is.EqualTo(@"..\")); + Assert.That(condition.Name, Is.EqualTo("MyFolder")); + Assert.That(condition.NotEmpty, Is.False); + } + + [Test] + public void Serialize_FolderExists_Correct() + { + var root = new ConditionXml() + { + Predicates = new List() + { + new FolderExistsConditionXml() + { + Path = ".", + Name = "myFolderName", + NotEmpty = false + } + } + }; + + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain("()); + var condition = ts.Tests[testNr].Condition.Predicates[0] as FileExistsConditionXml; + Assert.That(condition.Path, Is.EqualTo(@"..\")); + Assert.That(condition.Name, Is.EqualTo("MyFile.txt")); + Assert.That(condition.NotEmpty, Is.True); + } + + [Test] + public void Serialize_FileExists_Correct() + { + var root = new ConditionXml() + { + Predicates = new List() + { + new FileExistsConditionXml() + { + Path = "Folder\\", + Name = "myFileName.txt", + NotEmpty = true + } + } + }; + + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain(" - + select * from [NewUsers] - + - + Nikola Tesla @@ -54,7 +54,7 @@ Leonhard Euler - + - + select * from [NewUsers] - + - + select * from noWhere - + + + + + + + + select * from [NewUsers] + + + + + select * from noWhere + + + + + + + + + + select * from [NewUsers] + + + + + select * from noWhere + + + \ No newline at end of file diff --git a/NBi.Xml/Decoration/Condition/FileExistsConditionXml.cs b/NBi.Xml/Decoration/Condition/FileExistsConditionXml.cs new file mode 100644 index 000000000..a2e70e1cf --- /dev/null +++ b/NBi.Xml/Decoration/Condition/FileExistsConditionXml.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; + +namespace NBi.Xml.Decoration.Condition +{ + public class FileExistsConditionXml : DecorationConditionXml + { + [XmlAttribute("path")] + public string Path { get; set; } + + [XmlAttribute("name")] + public string Name { get; set; } + + [DefaultValue(false)] + [XmlAttribute("not-empty")] + public bool NotEmpty { get; set; } = false; + } +} diff --git a/NBi.Xml/Decoration/Condition/FolderExistsConditionXml.cs b/NBi.Xml/Decoration/Condition/FolderExistsConditionXml.cs new file mode 100644 index 000000000..297fb160d --- /dev/null +++ b/NBi.Xml/Decoration/Condition/FolderExistsConditionXml.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; + +namespace NBi.Xml.Decoration.Condition +{ + public class FolderExistsConditionXml : DecorationConditionXml + { + [XmlAttribute("path")] + public string Path { get; set; } + + [XmlAttribute("name")] + public string Name { get; set; } + + [DefaultValue(false)] + [XmlAttribute("not-empty")] + public bool NotEmpty { get; set; } = false; + } +} diff --git a/NBi.Xml/Decoration/Condition/ServiceRunningXml.cs b/NBi.Xml/Decoration/Condition/ServiceRunningConditionXml.cs similarity index 77% rename from NBi.Xml/Decoration/Condition/ServiceRunningXml.cs rename to NBi.Xml/Decoration/Condition/ServiceRunningConditionXml.cs index 2dd71e918..1c979e203 100644 --- a/NBi.Xml/Decoration/Condition/ServiceRunningXml.cs +++ b/NBi.Xml/Decoration/Condition/ServiceRunningConditionXml.cs @@ -1,22 +1,22 @@ -using System; -using System.ComponentModel; -using System.Linq; -using System.Xml.Serialization; - -namespace NBi.Xml.Decoration.Condition -{ - public class ServiceRunningXml : DecorationConditionXml - { - [XmlAttribute("name")] - public string ServiceName { get; set; } - - [XmlAttribute("timeout-milliseconds")] - [DefaultValue("5000")] - public string TimeOut { get; set; } - - public ServiceRunningXml() - { - TimeOut = "5000"; - } - } -} +using System; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; + +namespace NBi.Xml.Decoration.Condition +{ + public class ServiceRunningConditionXml : DecorationConditionXml + { + [XmlAttribute("name")] + public string ServiceName { get; set; } + + [XmlAttribute("timeout-milliseconds")] + [DefaultValue("5000")] + public string TimeOut { get; set; } + + public ServiceRunningConditionXml() + { + TimeOut = "5000"; + } + } +} diff --git a/NBi.Xml/Decoration/ConditionXml.cs b/NBi.Xml/Decoration/ConditionXml.cs index 49433410b..995845bd7 100644 --- a/NBi.Xml/Decoration/ConditionXml.cs +++ b/NBi.Xml/Decoration/ConditionXml.cs @@ -9,8 +9,10 @@ namespace NBi.Xml.Decoration public class ConditionXml { [ - XmlElement(Type = typeof(ServiceRunningXml), ElementName = "service-running"), - XmlElement(Type = typeof(CustomConditionXml), ElementName = "custom") + XmlElement(Type = typeof(ServiceRunningConditionXml), ElementName = "service-running"), + XmlElement(Type = typeof(CustomConditionXml), ElementName = "custom"), + XmlElement(Type = typeof(FolderExistsConditionXml), ElementName = "folder-exists"), + XmlElement(Type = typeof(FileExistsConditionXml), ElementName = "file-exists"), ] public List Predicates { get; set; } diff --git a/NBi.Xml/NBi.Xml.csproj b/NBi.Xml/NBi.Xml.csproj index 2d3384c94..a0f05eb07 100644 --- a/NBi.Xml/NBi.Xml.csproj +++ b/NBi.Xml/NBi.Xml.csproj @@ -133,7 +133,9 @@ - + + + diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 6c0fdc66c..16b207d59 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -520,6 +520,8 @@ + + @@ -537,6 +539,16 @@ + + + + + + + + + + From ac4ab15174cd9612e0bdb93ee24317c4bf5bde78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 6 Jan 2020 21:09:43 +0100 Subject: [PATCH 44/57] Implemntation in ConditionHelper --- NBi.NUnit/Builder/Helper/ConditionHelper.cs | 25 +++++++++++++++++++++ NBi.NUnit/Builder/Helper/ScalarHelper.cs | 6 +++++ 2 files changed, 31 insertions(+) diff --git a/NBi.NUnit/Builder/Helper/ConditionHelper.cs b/NBi.NUnit/Builder/Helper/ConditionHelper.cs index a9f2c4842..28f4cd32a 100644 --- a/NBi.NUnit/Builder/Helper/ConditionHelper.cs +++ b/NBi.NUnit/Builder/Helper/ConditionHelper.cs @@ -1,6 +1,7 @@ using NBi.Core; using NBi.Core.Assemblies.Decoration; using NBi.Core.Decoration; +using NBi.Core.Decoration.IO; using NBi.Core.Decoration.Process; using NBi.Core.Injection; using NBi.Core.Scalar.Resolver; @@ -32,6 +33,8 @@ public IDecorationConditionArgs Execute(object condition) { case CustomConditionXml custom: return BuildCustomCondition(custom); case ServiceRunningConditionXml serviceRunning: return BuildServiceRunning(serviceRunning); + case FileExistsConditionXml fileExists: return BuildFileExists(fileExists); + case FolderExistsConditionXml folderExists: return BuildFolderExists(folderExists); default: throw new ArgumentOutOfRangeException(); } } @@ -56,6 +59,28 @@ private IDecorationConditionArgs BuildServiceRunning(ServiceRunningConditionXml ); } + private IDecorationConditionArgs BuildFileExists(FileExistsConditionXml fileExists) + { + var scalarHelper = new ScalarHelper(serviceLocator, new Context(variables)); + return new FileExistsConditionArgs( + serviceLocator.BasePath + , scalarHelper.InstantiateResolver(fileExists.Path) + , scalarHelper.InstantiateResolver(fileExists.Name) + , scalarHelper.InstantiateResolver(fileExists.NotEmpty) + ); + } + + private IDecorationConditionArgs BuildFolderExists(FolderExistsConditionXml folderExists) + { + var scalarHelper = new ScalarHelper(serviceLocator, new Context(variables)); + return new FolderExistsConditionArgs( + serviceLocator.BasePath + , scalarHelper.InstantiateResolver(folderExists.Path) + , scalarHelper.InstantiateResolver(folderExists.Name) + , scalarHelper.InstantiateResolver(folderExists.NotEmpty) + ); + } + private class RunningArgs : IRunningConditionArgs { public RunningArgs(IScalarResolver serviceName, IScalarResolver timeOut) diff --git a/NBi.NUnit/Builder/Helper/ScalarHelper.cs b/NBi.NUnit/Builder/Helper/ScalarHelper.cs index 5707166f6..a5bdadb7e 100644 --- a/NBi.NUnit/Builder/Helper/ScalarHelper.cs +++ b/NBi.NUnit/Builder/Helper/ScalarHelper.cs @@ -63,6 +63,12 @@ public IScalarResolver InstantiateResolver(string value) return resolver; } + public IScalarResolver InstantiateResolver(bool value) + => InstantiateResolver(value.ToString()); + + public IScalarResolver InstantiateResolver(int value) + => InstantiateResolver(value.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat)); + public IScalarResolver InstantiateResolver(ColumnType columnType, string value) { var argsBuilder = new ScalarResolverArgsBuilder(ServiceLocator, Context); From 533f807c27c701d5d099908e513622dbd7dd9a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 6 Jan 2020 21:10:27 +0100 Subject: [PATCH 45/57] Add the message when the condition is failing --- .../IO/Conditions/FileExistsCondition.cs | 14 +++++++------- .../IO/Conditions/FolderExistsCondition.cs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs b/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs index a28097d46..61cf33f24 100644 --- a/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs +++ b/NBi.Core/Decoration/IO/Conditions/FileExistsCondition.cs @@ -13,7 +13,7 @@ class FileExistsCondition : IDecorationCondition { private FileExistsConditionArgs Args { get; } - public string Message => throw new NotImplementedException(); + public string Message { get; private set; } public FileExistsCondition(FileExistsConditionArgs args) => Args = args; @@ -21,21 +21,21 @@ public bool Validate() { var fullPath = PathExtensions.CombineOrRoot(Args.BasePath, Args.FolderName.Execute(), Args.FileName.Execute()); - var conditions = new List>() { ExistsCondition }; + var conditions = new List>() { ExistsCondition }; if (Args.NotEmpty.Execute()) conditions.Add(IsNotEmptyCondition); var result = true; var enumerator = conditions.GetEnumerator(); while (result && enumerator.MoveNext()) - result = enumerator.Current.Invoke(fullPath); + (result, Message) = enumerator.Current.Invoke(fullPath); return result; } - protected bool ExistsCondition(string fullPath) - => File.Exists(fullPath); + protected (bool, string) ExistsCondition(string fullPath) + => (File.Exists(fullPath), $"The file '{fullPath}' doesn't exists."); - protected bool IsNotEmptyCondition(string fullPath) - => new FileInfo(fullPath).Length > 0; + protected (bool, string) IsNotEmptyCondition(string fullPath) + => (new FileInfo(fullPath).Length > 0, $"The file '{fullPath}' has a size of 0 byte."); } } diff --git a/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs b/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs index bc96392c4..8f06c02af 100644 --- a/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs +++ b/NBi.Core/Decoration/IO/Conditions/FolderExistsCondition.cs @@ -13,7 +13,7 @@ class FolderExistsCondition : IDecorationCondition { private FolderExistsConditionArgs Args { get; } - public string Message => throw new NotImplementedException(); + public string Message { get; private set; } public FolderExistsCondition(FolderExistsConditionArgs args) => Args = args; @@ -22,21 +22,21 @@ public bool Validate() var path = PathExtensions.CombineOrRoot(Args.BasePath, Args.FolderPath.Execute()); var fullPath = PathExtensions.CombineOrRoot(path, Args.FolderName.Execute()); - var conditions = new List>() { ExistsCondition }; + var conditions = new List>() { ExistsCondition }; if (Args.NotEmpty.Execute()) conditions.Add(IsNotEmptyCondition); var result = true; var enumerator = conditions.GetEnumerator(); while (result && enumerator.MoveNext()) - result = enumerator.Current.Invoke(fullPath); + (result, Message) = enumerator.Current.Invoke(fullPath); return result; } - protected bool ExistsCondition(string fullPath) - => Directory.Exists(fullPath); + protected (bool, string) ExistsCondition(string fullPath) + => (Directory.Exists(fullPath), $"The file '{fullPath}' doesn't exists."); - protected bool IsNotEmptyCondition(string fullPath) - => !string.IsNullOrEmpty(Directory.EnumerateFiles(fullPath).FirstOrDefault()); + protected (bool, string) IsNotEmptyCondition(string fullPath) + => (!string.IsNullOrEmpty(Directory.EnumerateFiles(fullPath).FirstOrDefault()), $"The directory '{fullPath}' doesn't contain any file."); } } From bdacad0f83dfc4324a8fe3e0211f91780f961f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 6 Jan 2020 21:10:41 +0100 Subject: [PATCH 46/57] Add implementation at in the Factory --- NBi.Core/Decoration/DecorationFactory.cs | 1 + .../Decoration/Process/IoConditionFactory.cs | 22 +++++++++++++++++++ NBi.Core/NBi.Core.csproj | 1 + .../Decoration/DecorationFactoryTest.cs | 5 +++++ 4 files changed, 29 insertions(+) create mode 100644 NBi.Core/Decoration/Process/IoConditionFactory.cs diff --git a/NBi.Core/Decoration/DecorationFactory.cs b/NBi.Core/Decoration/DecorationFactory.cs index 3fc72dd65..7d519b118 100644 --- a/NBi.Core/Decoration/DecorationFactory.cs +++ b/NBi.Core/Decoration/DecorationFactory.cs @@ -32,6 +32,7 @@ public IDecorationCondition Instantiate(IDecorationConditionArgs args) switch (args) { case IProcessConditionArgs processArgs: return new ProcessConditionFactory().Instantiate(processArgs); + case IIoConditionArgs ioArgs: return new IoConditionFactory().Instantiate(ioArgs); case ICustomConditionArgs customConditionArgs: return new CustomConditionFactory().Instantiate(customConditionArgs); default: throw new ArgumentOutOfRangeException(); } diff --git a/NBi.Core/Decoration/Process/IoConditionFactory.cs b/NBi.Core/Decoration/Process/IoConditionFactory.cs new file mode 100644 index 000000000..56d6641cc --- /dev/null +++ b/NBi.Core/Decoration/Process/IoConditionFactory.cs @@ -0,0 +1,22 @@ +using NBi.Core.Decoration.IO; +using NBi.Core.Decoration.IO.Conditions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NBi.Core.Decoration.Process +{ + class IoConditionFactory + { + public IDecorationCondition Instantiate(IIoConditionArgs args) + { + switch (args) + { + case FolderExistsConditionArgs folderExistsArgs: return new FolderExistsCondition(folderExistsArgs); + case FileExistsConditionArgs fileExistsArgs: return new FileExistsCondition(fileExistsArgs); + default: throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index d12250df6..6ac0da13f 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -154,6 +154,7 @@ + diff --git a/NBi.Testing.Core/Decoration/DecorationFactoryTest.cs b/NBi.Testing.Core/Decoration/DecorationFactoryTest.cs index e569722f4..241de9932 100644 --- a/NBi.Testing.Core/Decoration/DecorationFactoryTest.cs +++ b/NBi.Testing.Core/Decoration/DecorationFactoryTest.cs @@ -20,6 +20,7 @@ using System.Reflection; using NBi.Extensibility.Decoration; using NBi.Extensibility.Decoration.DataEngineering; +using NBi.Core.Decoration.IO.Conditions; namespace NBi.Testing.Core.Decoration.DataEngineering { @@ -119,6 +120,8 @@ private IDecorationConditionArgs GetConditionArgsMock(Type type) switch (type) { case Type x when x == typeof(IRunningConditionArgs): return Mock.Of(); + case Type x when x == typeof(FolderExistsConditionArgs): return new FolderExistsConditionArgs(string.Empty, null, null, null); + case Type x when x == typeof(FileExistsConditionArgs): return new FileExistsConditionArgs (string.Empty, null, null, null); case Type x when x == typeof(ICustomConditionArgs): return Mock.Of ( y => y.AssemblyPath == new LiteralScalarResolver($@"{FileOnDisk.GetDirectoryPath()}\NBi.Testing.Core.dll") @@ -130,6 +133,8 @@ private IDecorationConditionArgs GetConditionArgsMock(Type type) [Test] [TestCase(typeof(IRunningConditionArgs), typeof(RunningCondition))] + [TestCase(typeof(FolderExistsConditionArgs), typeof(FolderExistsCondition))] + [TestCase(typeof(FileExistsConditionArgs), typeof(FileExistsCondition))] [TestCase(typeof(ICustomConditionArgs), typeof(CustomCondition))] public void Get_IDecorationConditionArgs_CorrectCondition(Type argsType, Type conditionType) { From 48dc5e1d6a73c484058a8b89bf218b30b2b2e2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 6 Jan 2020 22:45:03 +0100 Subject: [PATCH 47/57] Implement and test the aggregation and its factory --- NBi.Core/NBi.Core.csproj | 1 + .../Aggregation/AggregationArgs.cs | 2 ++ .../Aggregation/AggregationFactory.cs | 17 +++++++--- .../Aggregation/AggregationFunctionType.cs | 1 + .../Aggregation/Function/Average.cs | 2 +- .../Aggregation/Function/BaseAggregation.cs | 4 +-- .../Aggregation/Function/Concatenation.cs | 27 ++++++++++++++++ .../Aggregation/Function/Max.cs | 2 +- .../Aggregation/Function/Min.cs | 2 +- .../Aggregation/Function/Sum.cs | 2 +- .../Strategy/ReturnDefaultStrategy.cs | 17 +++++++++- NBi.Testing.Core/NBi.Testing.Core.csproj | 1 + .../Aggregation/AggregationFactoryTest.cs | 14 +++++++-- .../Aggregation/Text/ConcatenateTest.cs | 31 +++++++++++++++++++ 14 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 NBi.Core/Sequence/Transformation/Aggregation/Function/Concatenation.cs create mode 100644 NBi.Testing.Core/Sequence/Transformation/Aggregation/Text/ConcatenateTest.cs diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index e7a92a0c4..b058bacb9 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -769,6 +769,7 @@ + diff --git a/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs b/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs index b5356a088..d3e9fa038 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Core.Scalar.Resolver; using System; using System.Collections.Generic; using System.Linq; @@ -11,6 +12,7 @@ public class AggregationArgs { public ColumnType ColumnType { get; } public AggregationFunctionType Function { get; } + public IList Parameters { get; } = new List(); public IList Strategies { get; } = new List(); public AggregationArgs(AggregationFunctionType function, ColumnType columnType) diff --git a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs index ad4ac187f..110a02883 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs @@ -9,23 +9,32 @@ using NBi.Core.Sequence.Transformation.Aggregation.Strategy; using NBi.Core.Sequence.Transformation.Aggregation.Function; using System.Reflection; +using NBi.Core.Scalar.Resolver; namespace NBi.Core.Sequence.Transformation.Aggregation { public class AggregationFactory { - public Aggregation Instantiate(ColumnType columnType, AggregationFunctionType function, IAggregationStrategy[] strategies) + public Aggregation Instantiate(ColumnType columnType, AggregationFunctionType function, IScalarResolver[] parameters, IAggregationStrategy[] strategies) { var missingValue = (IMissingValueStrategy)(strategies.SingleOrDefault(x => x is IMissingValueStrategy) ?? new DropStrategy()); - var emptySeries = (IEmptySeriesStrategy)(strategies.SingleOrDefault(x => x is IEmptySeriesStrategy) ?? new ReturnDefaultStrategy(0)); + var emptySeries = (IEmptySeriesStrategy)(strategies.SingleOrDefault(x => x is IEmptySeriesStrategy) ?? new ReturnDefaultStrategy(columnType)); var @namespace = $"{this.GetType().Namespace}.Function."; var typeName = $"{Enum.GetName(typeof(AggregationFunctionType), function)}{Enum.GetName(typeof(ColumnType), columnType)}"; var type = GetType().Assembly.GetType($"{@namespace}{typeName}", false, true) ?? throw new ArgumentException($"No aggregation named '{typeName}' has been found in the namespace '{@namespace}'."); - return new Aggregation((IAggregationFunction)(type.GetConstructor(Type.EmptyTypes).Invoke(new object[] { })), missingValue, emptySeries); + + if ((parameters?.Count() ?? 0) == 0) + return new Aggregation((IAggregationFunction)(type.GetConstructor(Type.EmptyTypes).Invoke(Array.Empty())), missingValue, emptySeries); + else + { + var ctor = type.GetConstructors().Where(x => x.IsPublic && (x.GetParameters().Count() == parameters.Count())).FirstOrDefault() + ?? throw new ArgumentException($"No public constructor for the aggregation '{function}' expecting {parameters.Count()} parameters."); + return new Aggregation((IAggregationFunction)ctor.Invoke(parameters), missingValue, emptySeries); + } } public Aggregation Instantiate(AggregationArgs args) - => Instantiate(args.ColumnType, args.Function, args.Strategies.ToArray()); + => Instantiate(args.ColumnType, args.Function, args.Parameters.ToArray(), args.Strategies.ToArray()); } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFunctionType.cs b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFunctionType.cs index eb980c403..d264fb508 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFunctionType.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFunctionType.cs @@ -12,5 +12,6 @@ public enum AggregationFunctionType Sum, Max, Min, + Concatenation, } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/Average.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/Average.cs index 05562fc2b..a6c1b4c73 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Function/Average.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/Average.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Function { - abstract class Average : BaseNumericAggregation + abstract class Average : BaseAggregation { public Average(ICaster caster) : base(caster) { } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/BaseAggregation.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/BaseAggregation.cs index 67cb5bc23..c316df6d5 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Function/BaseAggregation.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/BaseAggregation.cs @@ -8,11 +8,11 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Function { - abstract class BaseNumericAggregation : IAggregationFunction + abstract class BaseAggregation : IAggregationFunction { protected ICaster Caster { get; } - public BaseNumericAggregation(ICaster caster) => Caster = caster; + public BaseAggregation(ICaster caster) => Caster = caster; public object Execute(IEnumerable values) { diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/Concatenation.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/Concatenation.cs new file mode 100644 index 000000000..4eaa76d2f --- /dev/null +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/Concatenation.cs @@ -0,0 +1,27 @@ +using Deedle; +using NBi.Core.Scalar.Casting; +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.Sequence.Transformation.Aggregation.Function +{ + abstract class Concatenation : BaseAggregation + { + protected IScalarResolver Separator { get; } + public Concatenation(ICaster caster, IScalarResolver separator) : base(caster) + => Separator = separator; + + protected override T Execute(Series series) + => Caster.Execute(string.Join(Separator.Execute(), series.Values.ToArray())); + } + + class ConcatenationText : Concatenation + { + public ConcatenationText(IScalarResolver separator) : base(new TextCaster(), separator) + { } + } +} diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/Max.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/Max.cs index 13a0b67c0..5ff1f3640 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Function/Max.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/Max.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Function { - abstract class Max : BaseNumericAggregation + abstract class Max : BaseAggregation { public Max(ICaster caster) : base(caster) { } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/Min.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/Min.cs index 498733d71..164c6994d 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Function/Min.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/Min.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Function { - abstract class Min : BaseNumericAggregation + abstract class Min : BaseAggregation { public Min(ICaster caster) : base(caster) { } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Function/Sum.cs b/NBi.Core/Sequence/Transformation/Aggregation/Function/Sum.cs index d20f421b7..e1c2683d2 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Function/Sum.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Function/Sum.cs @@ -8,7 +8,7 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Function { - abstract class Sum : BaseNumericAggregation + abstract class Sum : BaseAggregation { public Sum(ICaster caster) : base(caster) { } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs index 9bd1dd31a..bcdaac797 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.ResultSet; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,6 +12,20 @@ class ReturnDefaultStrategy : IEmptySeriesStrategy private object DefaultValue { get; } public ReturnDefaultStrategy(object defaultValue) => DefaultValue = defaultValue; + internal ReturnDefaultStrategy(ColumnType columnType) + : this(DefaultValueByColumnType(columnType)) { } + + private static object DefaultValueByColumnType(ColumnType columnType) + { + switch (columnType) + { + case ColumnType.Text: return string.Empty; + case ColumnType.Numeric: return 0; + case ColumnType.DateTime: return new DateTime(1900, 1, 1); + case ColumnType.Boolean: return false; + default: throw new ArgumentOutOfRangeException(); + } + } public object Execute() => DefaultValue; } diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 666e5f4b6..931d97a45 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -249,6 +249,7 @@ + diff --git a/NBi.Testing.Core/Sequence/Transformation/Aggregation/AggregationFactoryTest.cs b/NBi.Testing.Core/Sequence/Transformation/Aggregation/AggregationFactoryTest.cs index 14818fb92..c8419e8a8 100644 --- a/NBi.Testing.Core/Sequence/Transformation/Aggregation/AggregationFactoryTest.cs +++ b/NBi.Testing.Core/Sequence/Transformation/Aggregation/AggregationFactoryTest.cs @@ -1,4 +1,5 @@ using NBi.Core.ResultSet; +using NBi.Core.Scalar.Resolver; using NBi.Core.Sequence.Transformation.Aggregation; using NBi.Core.Sequence.Transformation.Aggregation.Function; using NBi.Core.Sequence.Transformation.Aggregation.Strategy; @@ -23,17 +24,26 @@ public class AggregationFactoryTest public void Instantiate_ColumnTypeandAggregationFunction_CorrectAggregation(ColumnType columnType, AggregationFunctionType function, Type expectedType) { var factory = new AggregationFactory(); - var aggregation = factory.Instantiate(columnType, function, new IAggregationStrategy[] {}); + var aggregation = factory.Instantiate(columnType, function, Array.Empty(), Array.Empty()); Assert.That(aggregation, Is.Not.Null); Assert.That(aggregation.Function, Is.TypeOf(expectedType)); } + [Test] + public void Instantiate_ConcantenationText_CorrectAggregation() + { + var factory = new AggregationFactory(); + var aggregation = factory.Instantiate(ColumnType.Text, AggregationFunctionType.Concatenation, new List { new LiteralScalarResolver("+")}.ToArray(), Array.Empty()); + Assert.That(aggregation, Is.Not.Null); + Assert.That(aggregation.Function, Is.TypeOf()); + } + [TestCase(ColumnType.DateTime, AggregationFunctionType.Sum)] [TestCase(ColumnType.DateTime, AggregationFunctionType.Average)] public void Instantiate_ColumnTypeAndAggregationFunction_CorrectAggregation(ColumnType columnType, AggregationFunctionType function) { var factory = new AggregationFactory(); - Assert.Throws( () => factory.Instantiate(columnType, function, new IAggregationStrategy[] { })); + Assert.Throws( () => factory.Instantiate(columnType, function, Array.Empty(), Array.Empty())); } } } diff --git a/NBi.Testing.Core/Sequence/Transformation/Aggregation/Text/ConcatenateTest.cs b/NBi.Testing.Core/Sequence/Transformation/Aggregation/Text/ConcatenateTest.cs new file mode 100644 index 000000000..919f752fc --- /dev/null +++ b/NBi.Testing.Core/Sequence/Transformation/Aggregation/Text/ConcatenateTest.cs @@ -0,0 +1,31 @@ +using NBi.Core.ResultSet; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Transformation.Aggregation.Function; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.Unit.Core.Sequence.Transformation.Aggregation.Text +{ + public class ConcatenationTest + { + [Test] + public void Execute_Text_CorrectValue() + { + var list = new List() { "alpha", "beta", "gamma"}; + var aggregation = new ConcatenationText(new LiteralScalarResolver("+")); + Assert.That(aggregation.Execute(list), Is.EqualTo("alpha+beta+gamma")); + } + + [Test] + public void Execute_EmptyValue_CorrectValue() + { + var list = new List(); + var aggregation = new ConcatenationText(new LiteralScalarResolver("+")); + Assert.That(aggregation.Execute(list), Is.EqualTo(string.Empty)); + } + } +} From 61f884062b008b62ee59895ff3fc47dcdd60c1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 7 Jan 2020 00:41:10 +0100 Subject: [PATCH 48/57] Fix issue with strategies heavily relying on NumericCaster when it should be a ICaster --- .../Summarization/ColumnAggregationArgs.cs | 9 +++--- NBi.Core/Scalar/Casting/DateTimeCaster.cs | 2 ++ NBi.Core/Scalar/Casting/ICaster.cs | 3 +- NBi.Core/Scalar/Casting/ImplicitCaster.cs | 1 + NBi.Core/Scalar/Casting/TextCaster.cs | 12 +++++++- .../Aggregation/AggregationArgs.cs | 4 +-- .../Aggregation/AggregationFactory.cs | 2 +- .../Aggregation/Strategy/DropStrategy.cs | 12 ++++++-- .../Strategy/FailureMissingValueStrategy.cs | 12 ++++++-- .../Strategy/IMissingValueStrategy.cs | 4 ++- .../Strategy/ReplaceByDefaultStrategy.cs | 12 +++++--- .../Strategy/ReturnDefaultStrategy.cs | 12 ++++---- .../Builder/Helper/ResultSetSystemHelper.cs | 5 +++- .../Summarization/SummarizeEngineTest.cs | 26 ++++++++-------- .../Strategy/DropStrategyTest.cs | 30 +++++++++++++++---- .../FailureMissingValueStrategyTest.cs | 11 +++---- .../Strategy/ReplaceByDefaultStrategyTest.cs | 11 +++---- 17 files changed, 112 insertions(+), 56 deletions(-) diff --git a/NBi.Core/ResultSet/Alteration/Summarization/ColumnAggregationArgs.cs b/NBi.Core/ResultSet/Alteration/Summarization/ColumnAggregationArgs.cs index bbbca9704..5370235bc 100644 --- a/NBi.Core/ResultSet/Alteration/Summarization/ColumnAggregationArgs.cs +++ b/NBi.Core/ResultSet/Alteration/Summarization/ColumnAggregationArgs.cs @@ -1,4 +1,5 @@ -using NBi.Core.Sequence.Transformation.Aggregation; +using NBi.Core.Scalar.Resolver; +using NBi.Core.Sequence.Transformation.Aggregation; using System; using System.Collections.Generic; using System.Linq; @@ -10,9 +11,9 @@ namespace NBi.Core.ResultSet.Alteration.Summarization public class ColumnAggregationArgs : AggregationArgs { public IColumnIdentifier Identifier { get; } - - public ColumnAggregationArgs(IColumnIdentifier identifier, AggregationFunctionType function, ColumnType columnType) - : base(function, columnType) + + public ColumnAggregationArgs(IColumnIdentifier identifier, AggregationFunctionType function, ColumnType columnType, IList parameters) + : base(function, columnType, parameters) => (Identifier) = (identifier); } } diff --git a/NBi.Core/Scalar/Casting/DateTimeCaster.cs b/NBi.Core/Scalar/Casting/DateTimeCaster.cs index c0e97ce19..7fc4ad0e5 100644 --- a/NBi.Core/Scalar/Casting/DateTimeCaster.cs +++ b/NBi.Core/Scalar/Casting/DateTimeCaster.cs @@ -96,5 +96,7 @@ public bool IsValid(object value) catch (Exception) { return false; } } + + public bool IsStrictlyValid(object value) => IsValid(value); } } diff --git a/NBi.Core/Scalar/Casting/ICaster.cs b/NBi.Core/Scalar/Casting/ICaster.cs index d9238e276..184802dd9 100644 --- a/NBi.Core/Scalar/Casting/ICaster.cs +++ b/NBi.Core/Scalar/Casting/ICaster.cs @@ -9,11 +9,12 @@ namespace NBi.Core.Scalar.Casting public interface ICaster: ICaster { new T Execute(object obj); - bool IsValid(object obj); } public interface ICaster { object Execute(object obj); + bool IsValid(object obj); + bool IsStrictlyValid(object obj); } } diff --git a/NBi.Core/Scalar/Casting/ImplicitCaster.cs b/NBi.Core/Scalar/Casting/ImplicitCaster.cs index 108c05f93..768ce8c1e 100644 --- a/NBi.Core/Scalar/Casting/ImplicitCaster.cs +++ b/NBi.Core/Scalar/Casting/ImplicitCaster.cs @@ -14,5 +14,6 @@ class ImplicitCaster : ICaster object ICaster.Execute(object value) => Execute(value); public bool IsValid(object value) => true; + public bool IsStrictlyValid(object value) => true; } } diff --git a/NBi.Core/Scalar/Casting/TextCaster.cs b/NBi.Core/Scalar/Casting/TextCaster.cs index d4b644e9e..ba1e335d6 100644 --- a/NBi.Core/Scalar/Casting/TextCaster.cs +++ b/NBi.Core/Scalar/Casting/TextCaster.cs @@ -18,8 +18,18 @@ public string Execute(object value) object ICaster.Execute(object value) => Execute(value); - public bool IsValid(object value) + public bool IsValid(object value) => true; + public bool IsStrictlyValid(object value) { + if (value == null) + return false; + + if (value == DBNull.Value) + return false; + + if (value is string && ((string) value) == "(null)") + return false; + return true; } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs b/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs index d3e9fa038..682553db1 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/AggregationArgs.cs @@ -15,7 +15,7 @@ public class AggregationArgs public IList Parameters { get; } = new List(); public IList Strategies { get; } = new List(); - public AggregationArgs(AggregationFunctionType function, ColumnType columnType) - => (ColumnType, Function) = (columnType, function); + public AggregationArgs(AggregationFunctionType function, ColumnType columnType, IList parameters) + => (ColumnType, Function, Parameters) = (columnType, function, parameters ?? new List()); } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs index 110a02883..0eb88484d 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/AggregationFactory.cs @@ -17,7 +17,7 @@ public class AggregationFactory { public Aggregation Instantiate(ColumnType columnType, AggregationFunctionType function, IScalarResolver[] parameters, IAggregationStrategy[] strategies) { - var missingValue = (IMissingValueStrategy)(strategies.SingleOrDefault(x => x is IMissingValueStrategy) ?? new DropStrategy()); + var missingValue = (IMissingValueStrategy)(strategies.SingleOrDefault(x => x is IMissingValueStrategy) ?? new DropStrategy(columnType)); var emptySeries = (IEmptySeriesStrategy)(strategies.SingleOrDefault(x => x is IEmptySeriesStrategy) ?? new ReturnDefaultStrategy(columnType)); var @namespace = $"{this.GetType().Namespace}.Function."; diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/DropStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/DropStrategy.cs index f126e2522..197ac815b 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/DropStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/DropStrategy.cs @@ -1,4 +1,5 @@ -using NBi.Core.Scalar.Casting; +using NBi.Core.ResultSet; +using NBi.Core.Scalar.Casting; using System; using System.Collections.Generic; using System.Linq; @@ -9,10 +10,15 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Strategy { public class DropStrategy : IMissingValueStrategy { + private ColumnType ColumnType { get; } + + public DropStrategy(ColumnType columnType) + => ColumnType = columnType; + public IEnumerable Execute(IEnumerable values) { - var caster = new NumericCaster(); - return values.Where(x => caster.IsValid(x)).Select(x => caster.Execute(x)).Cast(); + var caster = new CasterFactory().Instantiate(ColumnType); + return values.Where(x => caster.IsValid(x) && x!=null).Select(x => caster.Execute(x)).Cast(); } } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/FailureMissingValueStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/FailureMissingValueStrategy.cs index 621d97394..7e1d12ec6 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/FailureMissingValueStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/FailureMissingValueStrategy.cs @@ -1,4 +1,5 @@ -using NBi.Core.Scalar.Casting; +using NBi.Core.ResultSet; +using NBi.Core.Scalar.Casting; using System; using System.Collections.Generic; using System.Linq; @@ -9,10 +10,15 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Strategy { public class FailureMissingValueStrategy : IMissingValueStrategy { + private ColumnType ColumnType { get; } + + public FailureMissingValueStrategy(ColumnType columnType) + => ColumnType = columnType; + public IEnumerable Execute(IEnumerable values) { - var caster = new NumericCaster(); - if (values.All(x => caster.IsStrictlyValid(x))) + var caster = new CasterFactory().Instantiate(ColumnType); + if (values.All(x => ((NumericCaster)caster).IsStrictlyValid(x))) return values.Select(x => caster.Execute(x)).Cast(); else throw new ArgumentException(); diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/IMissingValueStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/IMissingValueStrategy.cs index 91db7e23a..047f18c8a 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/IMissingValueStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/IMissingValueStrategy.cs @@ -1,4 +1,6 @@ -using NBi.Core.Sequence.Transformation.Aggregation; +using NBi.Core.ResultSet; +using NBi.Core.Scalar.Casting; +using NBi.Core.Sequence.Transformation.Aggregation; using System; using System.Collections.Generic; using System.Linq; diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReplaceByDefaultStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReplaceByDefaultStrategy.cs index ea6fee65d..56ce63bc5 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReplaceByDefaultStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReplaceByDefaultStrategy.cs @@ -1,4 +1,5 @@ -using NBi.Core.Scalar.Casting; +using NBi.Core.ResultSet; +using NBi.Core.Scalar.Casting; using System; using System.Collections.Generic; using System.Linq; @@ -9,13 +10,16 @@ namespace NBi.Core.Sequence.Transformation.Aggregation.Strategy { public class ReplaceByDefaultStrategy : IMissingValueStrategy { - private decimal DefaultValue { get; } + private object DefaultValue { get; } - public ReplaceByDefaultStrategy(decimal defaultValue) => DefaultValue = defaultValue; + private ColumnType ColumnType { get; } + + public ReplaceByDefaultStrategy(ColumnType columnType, object defaultValue) + => (ColumnType, DefaultValue) = (columnType, defaultValue); public IEnumerable Execute(IEnumerable values) { - var caster = new NumericCaster(); + var caster = new CasterFactory().Instantiate(ColumnType); return values.Select(x => caster.IsStrictlyValid(x) ? caster.Execute(x) : DefaultValue).Cast(); } } diff --git a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs index bcdaac797..93537d18a 100644 --- a/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs +++ b/NBi.Core/Sequence/Transformation/Aggregation/Strategy/ReturnDefaultStrategy.cs @@ -12,17 +12,15 @@ class ReturnDefaultStrategy : IEmptySeriesStrategy private object DefaultValue { get; } public ReturnDefaultStrategy(object defaultValue) => DefaultValue = defaultValue; - internal ReturnDefaultStrategy(ColumnType columnType) - : this(DefaultValueByColumnType(columnType)) { } - private static object DefaultValueByColumnType(ColumnType columnType) + internal static ReturnDefaultStrategy Instantiate(ColumnType columnType) { switch (columnType) { - case ColumnType.Text: return string.Empty; - case ColumnType.Numeric: return 0; - case ColumnType.DateTime: return new DateTime(1900, 1, 1); - case ColumnType.Boolean: return false; + case ColumnType.Text: return new ReturnDefaultStrategy(string.Empty); + case ColumnType.Numeric: return new ReturnDefaultStrategy(0); + case ColumnType.DateTime: return new ReturnDefaultStrategy(new DateTime(1900, 1, 1)); + case ColumnType.Boolean: return new ReturnDefaultStrategy(false); default: throw new ArgumentOutOfRangeException(); } } diff --git a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs index 5642778c9..3ac780e78 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetSystemHelper.cs @@ -206,13 +206,16 @@ private Alter InstantiateTransform(TransformXml transformXml) private Alter InstantiateSummarize(SummarizeXml summarizeXml) { + var scalarHelper = new ScalarHelper(ServiceLocator, null); + var factory = new SummarizationFactory(); var aggregations = new List() { new ColumnAggregationArgs( summarizeXml.Aggregation.Identifier, summarizeXml.Aggregation.Function, - summarizeXml.Aggregation.ColumnType + summarizeXml.Aggregation.ColumnType, + summarizeXml.Aggregation.Parameters.Select(x => scalarHelper.InstantiateResolver(summarizeXml.Aggregation.ColumnType, x)).ToList() ) }; var groupBys = summarizeXml.GroupBy?.Columns?.Cast() ?? new List(); diff --git a/NBi.Testing.Core/ResultSet/Alteration/Summarization/SummarizeEngineTest.cs b/NBi.Testing.Core/ResultSet/Alteration/Summarization/SummarizeEngineTest.cs index afa99970d..a7e55010b 100644 --- a/NBi.Testing.Core/ResultSet/Alteration/Summarization/SummarizeEngineTest.cs +++ b/NBi.Testing.Core/ResultSet/Alteration/Summarization/SummarizeEngineTest.cs @@ -47,7 +47,7 @@ public void Execute_SingleKeySingleAggregation_ExpectedResultSet() var args = new SummarizeArgs( new List() - { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric) }, + { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null) }, new List() { Mock.Of(x => x.Identifier == new ColumnNameIdentifier("keyColumn") && x.Type == ColumnType.Text) } ); @@ -76,7 +76,7 @@ public void Execute_MultipleKeySingleAggregation_ExpectedResultSet() var args = new SummarizeArgs( new List() - { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric) }, + { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null) }, new List() { Mock.Of(x => x.Identifier == new ColumnNameIdentifier("ColumnA") && x.Type == ColumnType.Text), @@ -107,7 +107,7 @@ public void Execute_MultipleKeyNonAlphabeticalOrderSingleAggregation_ExpectedRes var args = new SummarizeArgs( new List() - { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric) }, + { new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null) }, new List() { Mock.Of(x => x.Identifier == new ColumnNameIdentifier("ColumnB") && x.Type == ColumnType.Text), @@ -133,9 +133,9 @@ public void Execute_SingleKeyMultipleAggregations_ExpectedResultSet() var args = new SummarizeArgs( new List() { - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric, null), }, new List() { Mock.Of(x => x.Identifier == new ColumnNameIdentifier("keyColumn") && x.Type == ColumnType.Text) } @@ -163,7 +163,7 @@ public void Execute_NoKeySingleAggregations_ExpectedResultSet() var args = new SummarizeArgs( new List() { - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null), }, new List() ); @@ -184,9 +184,9 @@ public void Execute_NoKeyMultipleAggregations_ExpectedResultSet() var args = new SummarizeArgs( new List() { - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric, null), }, new List() ); @@ -214,9 +214,9 @@ public void Execute_LargeResultSet_ExpectedPerformance(int count) var args = new SummarizeArgs( new List() { - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric), - new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Sum, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Min, ColumnType.Numeric, null), + new ColumnAggregationArgs(new ColumnNameIdentifier("valueColumn"), AggregationFunctionType.Max, ColumnType.Numeric, null), }, new List() { Mock.Of(x => x.Identifier == new ColumnNameIdentifier("keyColumn") && x.Type == ColumnType.Text) } diff --git a/NBi.Testing.Core/Sequence/Transformation/Strategy/DropStrategyTest.cs b/NBi.Testing.Core/Sequence/Transformation/Strategy/DropStrategyTest.cs index af07f516e..6dd831143 100644 --- a/NBi.Testing.Core/Sequence/Transformation/Strategy/DropStrategyTest.cs +++ b/NBi.Testing.Core/Sequence/Transformation/Strategy/DropStrategyTest.cs @@ -1,4 +1,5 @@ -using NBi.Core.Sequence.Transformation.Aggregation.Strategy; +using NBi.Core.ResultSet; +using NBi.Core.Sequence.Transformation.Aggregation.Strategy; using NUnit.Framework; using System; using System.Collections.Generic; @@ -14,7 +15,15 @@ public class DropStrategyTest public void Execute_NothingToDrop_NothingDropped() { var list = new List() { 1, 3, 5 }; - var strategy = new DropStrategy(); + var strategy = new DropStrategy(ColumnType.Numeric); + Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); + } + + [Test] + public void Execute_NothingToDropEvenIfText_NothingDropped() + { + var list = new List() { "1", "3", "5" }; + var strategy = new DropStrategy(ColumnType.Numeric); Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); } @@ -22,7 +31,7 @@ public void Execute_NothingToDrop_NothingDropped() public void Execute_NothingToDrop_SameValues() { var list = new List() { 1, 3, 5 }; - var strategy = new DropStrategy(); + var strategy = new DropStrategy(ColumnType.Numeric); Assert.That(strategy.Execute(list), Has.Member(1)); Assert.That(strategy.Execute(list), Has.Member(3)); Assert.That(strategy.Execute(list), Has.Member(5)); @@ -32,7 +41,7 @@ public void Execute_NothingToDrop_SameValues() public void Execute_Blank_BlankDropped() { var list = new List() { 1, "(blank)", 3, 5 }; - var strategy = new DropStrategy(); + var strategy = new DropStrategy(ColumnType.Numeric); Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); Assert.That(strategy.Execute(list), Has.Member(1)); Assert.That(strategy.Execute(list), Has.Member(3)); @@ -43,11 +52,22 @@ public void Execute_Blank_BlankDropped() public void Execute_Null_NullDropped() { var list = new List() { 1, 3, 5, null }; - var strategy = new DropStrategy(); + var strategy = new DropStrategy(ColumnType.Numeric); Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); Assert.That(strategy.Execute(list), Has.Member(1)); Assert.That(strategy.Execute(list), Has.Member(3)); Assert.That(strategy.Execute(list), Has.Member(5)); } + + [Test] + public void Execute_NumericForText_NullDroppedButNumericHeld() + { + var list = new List() { "foo", "bar", 1, null }; + var strategy = new DropStrategy(ColumnType.Text); + Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); + Assert.That(strategy.Execute(list), Has.Member("foo")); + Assert.That(strategy.Execute(list), Has.Member("bar")); + Assert.That(strategy.Execute(list), Has.Member("1")); + } } } diff --git a/NBi.Testing.Core/Sequence/Transformation/Strategy/FailureMissingValueStrategyTest.cs b/NBi.Testing.Core/Sequence/Transformation/Strategy/FailureMissingValueStrategyTest.cs index 1613e1ae4..2b355f67e 100644 --- a/NBi.Testing.Core/Sequence/Transformation/Strategy/FailureMissingValueStrategyTest.cs +++ b/NBi.Testing.Core/Sequence/Transformation/Strategy/FailureMissingValueStrategyTest.cs @@ -1,4 +1,5 @@ -using NBi.Core.Sequence.Transformation.Aggregation.Strategy; +using NBi.Core.ResultSet; +using NBi.Core.Sequence.Transformation.Aggregation.Strategy; using NUnit.Framework; using System; using System.Collections.Generic; @@ -14,7 +15,7 @@ public class FailureMissingValueStrategyTest public void Execute_NoSpecialValue_NoException() { var list = new List() { 1, 3, 5 }; - var strategy = new FailureMissingValueStrategy(); + var strategy = new FailureMissingValueStrategy(ColumnType.Numeric); Assert.DoesNotThrow(() => strategy.Execute(list)); } @@ -22,7 +23,7 @@ public void Execute_NoSpecialValue_NoException() public void Execute_NoSpecialValue_SameValues() { var list = new List() { 1, 3, 5 }; - var strategy = new FailureMissingValueStrategy(); + var strategy = new FailureMissingValueStrategy(ColumnType.Numeric); var result = strategy.Execute(list); Assert.That(result, Has.Member(1)); Assert.That(result, Has.Member(3)); @@ -33,7 +34,7 @@ public void Execute_NoSpecialValue_SameValues() public void Execute_Blank_BlankDropped() { var list = new List() { 1, "(blank)", 3, 5 }; - var strategy = new FailureMissingValueStrategy(); + var strategy = new FailureMissingValueStrategy(ColumnType.Numeric); Assert.Throws(() => strategy.Execute(list)); } @@ -41,7 +42,7 @@ public void Execute_Blank_BlankDropped() public void Execute_Null_NullDropped() { var list = new List() { 1, 3, 5, null }; - var strategy = new FailureMissingValueStrategy(); + var strategy = new FailureMissingValueStrategy(ColumnType.Numeric); Assert.Throws(() => strategy.Execute(list)); } } diff --git a/NBi.Testing.Core/Sequence/Transformation/Strategy/ReplaceByDefaultStrategyTest.cs b/NBi.Testing.Core/Sequence/Transformation/Strategy/ReplaceByDefaultStrategyTest.cs index 3fddfef0a..79d05d94b 100644 --- a/NBi.Testing.Core/Sequence/Transformation/Strategy/ReplaceByDefaultStrategyTest.cs +++ b/NBi.Testing.Core/Sequence/Transformation/Strategy/ReplaceByDefaultStrategyTest.cs @@ -1,4 +1,5 @@ -using NBi.Core.Sequence.Transformation.Aggregation.Strategy; +using NBi.Core.ResultSet; +using NBi.Core.Sequence.Transformation.Aggregation.Strategy; using NUnit.Framework; using System; using System.Collections.Generic; @@ -14,7 +15,7 @@ public class ReplaceByDefaultStrategyTest public void Execute_NothingToReplace_NothingDropped() { var list = new List() { 1, 3, 5 }; - var strategy = new ReplaceByDefaultStrategy(0); + var strategy = new ReplaceByDefaultStrategy(ColumnType.Numeric, 0); Assert.That(strategy.Execute(list).Count, Is.EqualTo(3)); } @@ -22,7 +23,7 @@ public void Execute_NothingToReplace_NothingDropped() public void Execute_NothingToReplace_SameValues() { var list = new List() { 1, 3, 5 }; - var strategy = new ReplaceByDefaultStrategy(0); + var strategy = new ReplaceByDefaultStrategy(ColumnType.Numeric, 0); Assert.That(strategy.Execute(list), Has.Member(1)); Assert.That(strategy.Execute(list), Has.Member(3)); Assert.That(strategy.Execute(list), Has.Member(5)); @@ -32,7 +33,7 @@ public void Execute_NothingToReplace_SameValues() public void Execute_Blank_BlankReplaced() { var list = new List() { 1, "(blank)", 3, 5 }; - var strategy = new ReplaceByDefaultStrategy(-1); + var strategy = new ReplaceByDefaultStrategy(ColumnType.Numeric, -1); Assert.That(strategy.Execute(list).Count, Is.EqualTo(4)); Assert.That(strategy.Execute(list), Has.Member(-1)); Assert.That(strategy.Execute(list), Has.Member(1)); @@ -44,7 +45,7 @@ public void Execute_Blank_BlankReplaced() public void Execute_Null_NullReplaced() { var list = new List() { 1, 3, 5, null }; - var strategy = new ReplaceByDefaultStrategy(0); + var strategy = new ReplaceByDefaultStrategy(ColumnType.Numeric, 0); Assert.That(strategy.Execute(list).Count, Is.EqualTo(4)); Assert.That(strategy.Execute(list), Has.Member(0)); Assert.That(strategy.Execute(list), Has.Member(1)); From 8a83d2b859cd0f02d0c70176b9530abd104d87af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 7 Jan 2020 00:41:47 +0100 Subject: [PATCH 49/57] Implement serialization of ConcatenationXml --- .../Systems/ResultSetSystemXmlTest.cs | 20 ++++++++++++++++++- .../Summarization/AggregationXml.cs | 16 ++++++++++++++- .../Alteration/Summarization/SummarizeXml.cs | 1 + NBi.Xml/Schema/BaseType.xsd | 8 ++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs index 710d59bc2..70dcdfa0c 100644 --- a/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs +++ b/NBi.Testing.Xml/Systems/ResultSetSystemXmlTest.cs @@ -528,7 +528,7 @@ public void Serialize_Renaming_Correct() [TestCase(typeof(AverageXml), "average")] [TestCase(typeof(MaxXml), "max")] [TestCase(typeof(MinXml), "min")] - public void Serialize_Sum_Correct(Type aggregationType, string serialization) + public void Serialize_SimpleAggregation_Correct(Type aggregationType, string serialization) { var root = new SummarizeXml() { @@ -544,6 +544,24 @@ public void Serialize_Sum_Correct(Type aggregationType, string serialization) Assert.That(xml, Does.Contain("dateTime")); } + [Test] + public void Serialize_Concatenation_Correct() + { + var root = new SummarizeXml() + { + Aggregation = new ConcatenationXml() { Separator="+" } + }; + root.Aggregation.ColumnType = ColumnType.Text; + root.Aggregation.Identifier = new ColumnOrdinalIdentifier(2); + + var manager = new XmlManager(); + var xml = manager.XmlSerializeFrom(root); + Console.WriteLine(xml); + Assert.That(xml, Does.Contain($" Parameters => Array.Empty(); } public class SumXml : AggregationXml { - public SumXml() : base(AggregationFunctionType.Sum) { } + public SumXml() : base(AggregationFunctionType.Sum) { } } public class AverageXml : AggregationXml @@ -50,4 +53,15 @@ public class MinXml : AggregationXml { public MinXml() : base(AggregationFunctionType.Min) { } } + + public class ConcatenationXml : AggregationXml + { + public ConcatenationXml() : base(AggregationFunctionType.Concatenation) { } + + [XmlAttribute("separator")] + public string Separator { get; set; } + + [XmlIgnore] + public override IEnumerable Parameters => new List() { Separator }; + } } \ No newline at end of file diff --git a/NBi.Xml/Items/Alteration/Summarization/SummarizeXml.cs b/NBi.Xml/Items/Alteration/Summarization/SummarizeXml.cs index 0a3714767..898122dcb 100644 --- a/NBi.Xml/Items/Alteration/Summarization/SummarizeXml.cs +++ b/NBi.Xml/Items/Alteration/Summarization/SummarizeXml.cs @@ -14,6 +14,7 @@ public class SummarizeXml : AlterationXml XmlElement(Type = typeof(MinXml), ElementName = "min"), XmlElement(Type = typeof(MaxXml), ElementName = "max"), XmlElement(Type = typeof(AverageXml), ElementName = "average"), + XmlElement(Type = typeof(ConcatenationXml), ElementName = "concatenation"), ] public AggregationXml Aggregation { get; set; } diff --git a/NBi.Xml/Schema/BaseType.xsd b/NBi.Xml/Schema/BaseType.xsd index 16b207d59..d521d0457 100644 --- a/NBi.Xml/Schema/BaseType.xsd +++ b/NBi.Xml/Schema/BaseType.xsd @@ -739,6 +739,7 @@ + @@ -753,6 +754,13 @@ + + + + + + + From da500c163fd01b5e36eab27149e4c1f7710afb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 7 Jan 2020 00:42:03 +0100 Subject: [PATCH 50/57] Add acceptance test --- .../Positive/ResultSetConstraint.nbits | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index 432616803..a68f26b78 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -1643,7 +1643,42 @@ - + + + + + select 'A' as Key1, 'alpha' as Value + union all select 'B', 'foo' + union all select 'B', 'bar' + union all select 'A', 'beta' + union all select 'A', 'gamma' + + + + + + + + + + + + + + + + A + alpha+beta+gamma + + + B + foo+bar + + + + + + @@ -1670,7 +1705,7 @@ - + @@ -1712,7 +1747,7 @@ - + From 9ae1862d4c1ff64b18f1ee97413d4451527b7479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 7 Jan 2020 00:43:39 +0100 Subject: [PATCH 51/57] Fix System.ValueTuple having different versions, update Moq and add developmentDependecy for NUnit3TestAdapter --- NBi.Core/NBi.Core.csproj | 2 +- NBi.Core/packages.config | 2 +- NBi.Testing.Core/NBi.Testing.Core.csproj | 5 ++++- NBi.Testing.Core/packages.config | 5 +++-- NBi.Testing.Framework/NBi.Testing.Framework.csproj | 5 ++++- NBi.Testing.Framework/packages.config | 5 +++-- NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj | 3 +++ NBi.Testing.GenbiL/packages.config | 3 ++- NBi.Testing.Xml/NBi.Testing.Xml.csproj | 3 +++ NBi.Testing.Xml/packages.config | 3 ++- NBi.Testing/NBi.Testing.csproj | 2 +- NBi.Testing/packages.config | 2 +- 12 files changed, 28 insertions(+), 12 deletions(-) diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index b058bacb9..efe71fb20 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -70,7 +70,7 @@ ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll - ..\packages\Moq.4.13.0\lib\net45\Moq.dll + ..\packages\Moq.4.13.1\lib\net45\Moq.dll ..\packages\NCalc-Edge.1.5.0\lib\net35\NCalc.dll diff --git a/NBi.Core/packages.config b/NBi.Core/packages.config index 45f98ba94..9edb32f9d 100644 --- a/NBi.Core/packages.config +++ b/NBi.Core/packages.config @@ -7,7 +7,7 @@ - + diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 931d97a45..1ccc72434 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -54,7 +54,7 @@ ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll - ..\packages\Moq.4.13.0\lib\net45\Moq.dll + ..\packages\Moq.4.13.1\lib\net45\Moq.dll ..\packages\NCalc-Edge.1.5.0\lib\net35\NCalc.dll @@ -74,6 +74,9 @@ ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + diff --git a/NBi.Testing.Core/packages.config b/NBi.Testing.Core/packages.config index 9f77c02c0..5741954c7 100644 --- a/NBi.Testing.Core/packages.config +++ b/NBi.Testing.Core/packages.config @@ -5,10 +5,11 @@ - + - + + \ No newline at end of file diff --git a/NBi.Testing.Framework/NBi.Testing.Framework.csproj b/NBi.Testing.Framework/NBi.Testing.Framework.csproj index e056e8d53..a5299a1d6 100644 --- a/NBi.Testing.Framework/NBi.Testing.Framework.csproj +++ b/NBi.Testing.Framework/NBi.Testing.Framework.csproj @@ -42,7 +42,7 @@ ..\packages\MarkdownLog.0.9.64\lib\netstandard2.0\MarkdownLog.dll - ..\packages\Moq.4.13.0\lib\net45\Moq.dll + ..\packages\Moq.4.13.1\lib\net45\Moq.dll ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll @@ -59,6 +59,9 @@ ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + diff --git a/NBi.Testing.Framework/packages.config b/NBi.Testing.Framework/packages.config index ccace1ba7..298722e64 100644 --- a/NBi.Testing.Framework/packages.config +++ b/NBi.Testing.Framework/packages.config @@ -2,9 +2,10 @@ - + - + + \ No newline at end of file diff --git a/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj b/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj index 246eb57d2..ea835a0d3 100644 --- a/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj +++ b/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj @@ -44,6 +44,9 @@ + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + diff --git a/NBi.Testing.GenbiL/packages.config b/NBi.Testing.GenbiL/packages.config index 7f2a8bf8d..117e32f1a 100644 --- a/NBi.Testing.GenbiL/packages.config +++ b/NBi.Testing.GenbiL/packages.config @@ -1,5 +1,6 @@  - + + \ No newline at end of file diff --git a/NBi.Testing.Xml/NBi.Testing.Xml.csproj b/NBi.Testing.Xml/NBi.Testing.Xml.csproj index 97da65c91..9b73b64e4 100644 --- a/NBi.Testing.Xml/NBi.Testing.Xml.csproj +++ b/NBi.Testing.Xml/NBi.Testing.Xml.csproj @@ -40,6 +40,9 @@ + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + diff --git a/NBi.Testing.Xml/packages.config b/NBi.Testing.Xml/packages.config index 6acefc3c8..cdbf24d3d 100644 --- a/NBi.Testing.Xml/packages.config +++ b/NBi.Testing.Xml/packages.config @@ -1,5 +1,6 @@  - + + \ No newline at end of file diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 383885638..2c46e95e8 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -70,7 +70,7 @@ ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll - ..\packages\Moq.4.13.0\lib\net45\Moq.dll + ..\packages\Moq.4.13.1\lib\net45\Moq.dll ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll diff --git a/NBi.Testing/packages.config b/NBi.Testing/packages.config index 5b70eca16..974cd5a2d 100644 --- a/NBi.Testing/packages.config +++ b/NBi.Testing/packages.config @@ -5,7 +5,7 @@ - + From 00b20c83ba529a797a66a3b0f902c004afa9d718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 7 Jan 2020 00:50:35 +0100 Subject: [PATCH 52/57] Update Deedle, AdoMDClient and RestSharp --- NBi.Core/NBi.Core.csproj | 18 +++++++++--------- NBi.Core/packages.config | 6 +++--- NBi.Testing.Core/NBi.Testing.Core.csproj | 12 ++++++------ NBi.Testing.Core/packages.config | 4 ++-- NBi.Testing/NBi.Testing.csproj | 12 ++++++------ NBi.Testing/packages.config | 4 ++-- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index e7a92a0c4..c0f09ffbb 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -51,23 +51,23 @@ ..\packages\StringTemplate4.4.0.8\lib\net35-client\Antlr4.StringTemplate.dll - - ..\packages\Deedle.2.0.4\lib\net45\Deedle.dll - ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll + + ..\packages\Deedle.2.1.0\lib\net45\Deedle.dll + ..\packages\FSharp.Core.4.7.0\lib\net45\FSharp.Core.dll ..\packages\FuzzyString.1.0.0\lib\FuzzyString.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll ..\packages\Moq.4.13.0\lib\net45\Moq.dll @@ -84,8 +84,8 @@ ..\packages\PocketCsvReader.1.0.0\lib\net461\PocketCsvReader.dll - - ..\packages\RestSharp.106.6.10\lib\net452\RestSharp.dll + + ..\packages\RestSharp.106.9.0\lib\net452\RestSharp.dll diff --git a/NBi.Core/packages.config b/NBi.Core/packages.config index 45f98ba94..5a130f22f 100644 --- a/NBi.Core/packages.config +++ b/NBi.Core/packages.config @@ -3,16 +3,16 @@ - + - + - + diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index 666e5f4b6..517777fe6 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -41,17 +41,17 @@ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll - - ..\packages\Deedle.2.0.4\lib\net45\Deedle.dll + + ..\packages\Deedle.2.1.0\lib\net45\Deedle.dll ..\packages\FSharp.Core.4.7.0\lib\net45\FSharp.Core.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll ..\packages\Moq.4.13.0\lib\net45\Moq.dll diff --git a/NBi.Testing.Core/packages.config b/NBi.Testing.Core/packages.config index 9f77c02c0..8c7bb83f5 100644 --- a/NBi.Testing.Core/packages.config +++ b/NBi.Testing.Core/packages.config @@ -2,9 +2,9 @@ - + - + diff --git a/NBi.Testing/NBi.Testing.csproj b/NBi.Testing/NBi.Testing.csproj index 383885638..15604c47f 100644 --- a/NBi.Testing/NBi.Testing.csproj +++ b/NBi.Testing/NBi.Testing.csproj @@ -54,8 +54,8 @@ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll - - ..\packages\Deedle.2.0.4\lib\net45\Deedle.dll + + ..\packages\Deedle.2.1.0\lib\net45\Deedle.dll ..\packages\FSharp.Core.4.7.0\lib\net45\FSharp.Core.dll @@ -63,11 +63,11 @@ ..\packages\MarkdownLog.0.9.64\lib\netstandard2.0\MarkdownLog.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.AdomdClient.dll - - ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.0.2\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll + + ..\packages\Microsoft.AnalysisServices.AdomdClient.retail.amd64.18.2.3\lib\net45\Microsoft.AnalysisServices.SPClient.Interfaces.dll ..\packages\Moq.4.13.0\lib\net45\Moq.dll diff --git a/NBi.Testing/packages.config b/NBi.Testing/packages.config index 5b70eca16..729a52971 100644 --- a/NBi.Testing/packages.config +++ b/NBi.Testing/packages.config @@ -1,10 +1,10 @@  - + - + From dbc1c2debaae64f8226563bf0ecd221198d96ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 14 Jan 2020 23:04:00 +0100 Subject: [PATCH 53/57] Huge refactoring to split between reader and Flattenizer --- .../DataSerializationProcessor.cs | 28 ++++++ .../DataSerializationProcessorFactory.cs | 21 +++++ .../DataSerializationType.cs | 14 +++ .../Flattening}/AttributeSelect.cs | 2 +- .../DataSerializationFlattenizerFactory.cs | 23 +++++ .../Flattening/ElementSelect.cs} | 6 +- .../Flattening}/EvaluateSelect.cs | 2 +- .../IDataSerializationFlattenizer.cs | 14 +++ .../Flattening/IFlattenizerArgs.cs | 13 +++ .../Flattening/IPathSelect.cs | 13 +++ .../Flattening/Json/JsonPathArgs.cs | 16 ++++ .../Flattening}/Json/JsonPathEngine.cs | 28 +++--- .../Flattening/PathFlattenizer.cs | 26 +++++ .../Flattening/PathFlattenizerFactory.cs} | 6 +- .../Flattening/Xml/XPathArgs.cs | 19 ++++ .../Flattening}/Xml/XPathEngine.cs | 23 +++-- .../Xml/XmlIgnoreNamespaceReader.cs | 2 +- .../Flattening}/Xml/XmlWrappingReader.cs | 2 +- .../Reader/DataSerializationReaderFactory.cs | 22 +++++ .../Reader/FileReader.cs} | 42 +++++---- .../Reader/FileReaderArgs.cs | 18 ++++ .../Reader/IDataSerializationReader.cs | 14 +++ .../DataSerialization/Reader/IReaderArgs.cs | 13 +++ .../DataSerialization/Reader/RestReader.cs | 47 ++++++++++ .../Reader/RestReaderArgs.cs | 18 ++++ .../DataSerialization/Reader/UrlReader.cs | 53 +++++++++++ .../DataSerialization/Reader/UrlReaderArgs.cs | 17 ++++ NBi.Core/Hierarchical/AbstractPathEngine.cs | 26 ----- NBi.Core/Hierarchical/ElementSelect.cs | 14 --- .../Hierarchical/Json/JsonPathRestEngine.cs | 31 ------ .../Hierarchical/Json/JsonPathUrlEngine.cs | 37 -------- NBi.Core/Hierarchical/Xml/XPathFileEngine.cs | 45 --------- NBi.Core/Hierarchical/Xml/XPathRestEngine.cs | 34 ------- NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs | 29 ------ NBi.Core/NBi.Core.csproj | 47 ++++++---- ... => DataSerializationResultSetResolver.cs} | 15 +-- .../DataSerializationResultSetResolverArgs.cs | 22 +++++ .../Resolver/ResultSetResolverFactory.cs | 5 +- .../Resolver/XPathResultSetResolverArgs.cs | 20 ---- NBi.Core/ResultSet/ResultSetServiceBuilder.cs | 3 - .../Scalar/Resolver/ScalarResolverFactory.cs | 3 - .../Helper/ResultSetResolverArgsBuilder.cs | 67 ++++++++----- NBi.NUnit/Builder/ResultSetEqualToBuilder.cs | 9 -- NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs | 13 --- NBi.NUnit/Builder/ScalarScoreBuilder.cs | 18 ---- .../BaseResultSetComparisonConstraint.cs | 7 -- NBi.NUnit/Scoring/ScoreConstraint.cs | 13 --- .../Flattenizer/JsonPathEngineTest.cs} | 56 ++++------- .../Resources/PurchaseOrders.json | 0 .../Flattenizer}/Resources/PurchaseOrders.xml | 0 .../PurchaseOrdersDefaultNamespace.xml | 0 .../PurchaseOrdersManyNamespaces.xml | 0 .../Flattenizer}/XPathEngineTest.cs | 94 ++++++------------- .../Json/JsonPathUrlEngineTest.cs | 47 ---------- NBi.Testing.Core/NBi.Testing.Core.csproj | 13 ++- 55 files changed, 607 insertions(+), 563 deletions(-) create mode 100644 NBi.Core/DataSerialization/DataSerializationProcessor.cs create mode 100644 NBi.Core/DataSerialization/DataSerializationProcessorFactory.cs create mode 100644 NBi.Core/DataSerialization/DataSerializationType.cs rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/AttributeSelect.cs (88%) create mode 100644 NBi.Core/DataSerialization/Flattening/DataSerializationFlattenizerFactory.cs rename NBi.Core/{Hierarchical/AbstractSelect.cs => DataSerialization/Flattening/ElementSelect.cs} (59%) rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/EvaluateSelect.cs (84%) create mode 100644 NBi.Core/DataSerialization/Flattening/IDataSerializationFlattenizer.cs create mode 100644 NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs create mode 100644 NBi.Core/DataSerialization/Flattening/IPathSelect.cs create mode 100644 NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/Json/JsonPathEngine.cs (74%) create mode 100644 NBi.Core/DataSerialization/Flattening/PathFlattenizer.cs rename NBi.Core/{Hierarchical/HierarchicalSelectFactory.cs => DataSerialization/Flattening/PathFlattenizerFactory.cs} (69%) create mode 100644 NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/Xml/XPathEngine.cs (77%) rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/Xml/XmlIgnoreNamespaceReader.cs (89%) rename NBi.Core/{Hierarchical => DataSerialization/Flattening}/Xml/XmlWrappingReader.cs (98%) create mode 100644 NBi.Core/DataSerialization/Reader/DataSerializationReaderFactory.cs rename NBi.Core/{Hierarchical/Json/JsonPathFileEngine.cs => DataSerialization/Reader/FileReader.cs} (51%) create mode 100644 NBi.Core/DataSerialization/Reader/FileReaderArgs.cs create mode 100644 NBi.Core/DataSerialization/Reader/IDataSerializationReader.cs create mode 100644 NBi.Core/DataSerialization/Reader/IReaderArgs.cs create mode 100644 NBi.Core/DataSerialization/Reader/RestReader.cs create mode 100644 NBi.Core/DataSerialization/Reader/RestReaderArgs.cs create mode 100644 NBi.Core/DataSerialization/Reader/UrlReader.cs create mode 100644 NBi.Core/DataSerialization/Reader/UrlReaderArgs.cs delete mode 100644 NBi.Core/Hierarchical/AbstractPathEngine.cs delete mode 100644 NBi.Core/Hierarchical/ElementSelect.cs delete mode 100644 NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs delete mode 100644 NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs delete mode 100644 NBi.Core/Hierarchical/Xml/XPathFileEngine.cs delete mode 100644 NBi.Core/Hierarchical/Xml/XPathRestEngine.cs delete mode 100644 NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs rename NBi.Core/ResultSet/Resolver/{XPathResultSetResolver.cs => DataSerializationResultSetResolver.cs} (60%) create mode 100644 NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolverArgs.cs delete mode 100644 NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs rename NBi.Testing.Core/{Hierarchical/Json/JsonPathFileEngineTest.cs => DataSerialization/Flattenizer/JsonPathEngineTest.cs} (77%) rename NBi.Testing.Core/{Hierarchical/Json => DataSerialization/Flattenizer}/Resources/PurchaseOrders.json (100%) rename NBi.Testing.Core/{Hierarchical/Xml => DataSerialization/Flattenizer}/Resources/PurchaseOrders.xml (100%) rename NBi.Testing.Core/{Hierarchical/Xml => DataSerialization/Flattenizer}/Resources/PurchaseOrdersDefaultNamespace.xml (100%) rename NBi.Testing.Core/{Hierarchical/Xml => DataSerialization/Flattenizer}/Resources/PurchaseOrdersManyNamespaces.xml (100%) rename NBi.Testing.Core/{Hierarchical/Xml => DataSerialization/Flattenizer}/XPathEngineTest.cs (71%) delete mode 100644 NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs diff --git a/NBi.Core/DataSerialization/DataSerializationProcessor.cs b/NBi.Core/DataSerialization/DataSerializationProcessor.cs new file mode 100644 index 000000000..5471719d3 --- /dev/null +++ b/NBi.Core/DataSerialization/DataSerializationProcessor.cs @@ -0,0 +1,28 @@ +using NBi.Core.DataSerialization.Flattening; +using NBi.Core.DataSerialization.Reader; +using NBi.Core.ResultSet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization +{ + public class DataSerializationProcessor + { + public IDataSerializationFlattenizer Flattenizer { get; } + public IDataSerializationReader Reader { get; } + + public DataSerializationProcessor(IDataSerializationReader reader, IDataSerializationFlattenizer flattenizer) + => (Reader, Flattenizer) = (reader, flattenizer); + + public IEnumerable Execute() + { + var textReader = Reader.Execute(); + var result = Flattenizer.Execute(textReader); + Reader.Dispose(); + return result; + } + } +} diff --git a/NBi.Core/DataSerialization/DataSerializationProcessorFactory.cs b/NBi.Core/DataSerialization/DataSerializationProcessorFactory.cs new file mode 100644 index 000000000..132ecd602 --- /dev/null +++ b/NBi.Core/DataSerialization/DataSerializationProcessorFactory.cs @@ -0,0 +1,21 @@ +using NBi.Core.DataSerialization.Flattening; +using NBi.Core.DataSerialization.Reader; +using NBi.Core.ResultSet.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization +{ + public class DataSerializationProcessorFactory + { + public DataSerializationProcessor Instantiate(DataSerializationResultSetResolverArgs args) + { + var reader = new DataSerializationReaderFactory().Instantiate(args.Reader); + var flattenizer = new DataSerializationFlattenizerFactory().Instantiate(args.Flattenizer); + return new DataSerializationProcessor(reader, flattenizer); + } + } +} diff --git a/NBi.Core/DataSerialization/DataSerializationType.cs b/NBi.Core/DataSerialization/DataSerializationType.cs new file mode 100644 index 000000000..8860db4e2 --- /dev/null +++ b/NBi.Core/DataSerialization/DataSerializationType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization +{ + public enum DataSerializationType + { + Json = 1, + Xml = 2, + } +} diff --git a/NBi.Core/Hierarchical/AttributeSelect.cs b/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs similarity index 88% rename from NBi.Core/Hierarchical/AttributeSelect.cs rename to NBi.Core/DataSerialization/Flattening/AttributeSelect.cs index b7d1590e2..c469f7d87 100644 --- a/NBi.Core/Hierarchical/AttributeSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Hierarchical +namespace NBi.Core.DataSerialization.Flattening { public class AttributeSelect: ElementSelect { diff --git a/NBi.Core/DataSerialization/Flattening/DataSerializationFlattenizerFactory.cs b/NBi.Core/DataSerialization/Flattening/DataSerializationFlattenizerFactory.cs new file mode 100644 index 000000000..679193f5d --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/DataSerializationFlattenizerFactory.cs @@ -0,0 +1,23 @@ +using NBi.Core.DataSerialization.Flattening.Json; +using NBi.Core.DataSerialization.Flattening.Xml; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening +{ + class DataSerializationFlattenizerFactory + { + public IDataSerializationFlattenizer Instantiate(IFlattenizerArgs args) + { + switch (args) + { + case XPathArgs xpathArgs: return new XPathEngine(xpathArgs.From, xpathArgs.Selects, xpathArgs.DefaultNamespacePrefix, xpathArgs.IsIgnoreNamespace); + case JsonPathArgs jsonPathArgs: return new JsonPathEngine(jsonPathArgs.From, jsonPathArgs.Selects); + default: throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/NBi.Core/Hierarchical/AbstractSelect.cs b/NBi.Core/DataSerialization/Flattening/ElementSelect.cs similarity index 59% rename from NBi.Core/Hierarchical/AbstractSelect.cs rename to NBi.Core/DataSerialization/Flattening/ElementSelect.cs index f31366f06..211c997a5 100644 --- a/NBi.Core/Hierarchical/AbstractSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/ElementSelect.cs @@ -4,13 +4,13 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Hierarchical +namespace NBi.Core.DataSerialization.Flattening { - public class AbstractSelect + public class ElementSelect : IPathSelect { public string Path { get; } - protected AbstractSelect(string path) + internal ElementSelect(string path) => Path = path; } } diff --git a/NBi.Core/Hierarchical/EvaluateSelect.cs b/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs similarity index 84% rename from NBi.Core/Hierarchical/EvaluateSelect.cs rename to NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs index 6dc288124..883793047 100644 --- a/NBi.Core/Hierarchical/EvaluateSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Hierarchical +namespace NBi.Core.DataSerialization.Flattening { public class EvaluateSelect: ElementSelect { diff --git a/NBi.Core/DataSerialization/Flattening/IDataSerializationFlattenizer.cs b/NBi.Core/DataSerialization/Flattening/IDataSerializationFlattenizer.cs new file mode 100644 index 000000000..892276259 --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/IDataSerializationFlattenizer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening +{ + public interface IDataSerializationFlattenizer + { + IEnumerable Execute(TextReader textReader); + } +} diff --git a/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs b/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs new file mode 100644 index 000000000..ab85543cf --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening +{ + public interface IFlattenizerArgs + { + IEnumerable Selects { get; } + } +} diff --git a/NBi.Core/DataSerialization/Flattening/IPathSelect.cs b/NBi.Core/DataSerialization/Flattening/IPathSelect.cs new file mode 100644 index 000000000..9889c3cb7 --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/IPathSelect.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening +{ + public interface IPathSelect + { + string Path { get; } + } +} diff --git a/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs b/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs new file mode 100644 index 000000000..728de6b6c --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs @@ -0,0 +1,16 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening.Json +{ + public class JsonPathArgs : IFlattenizerArgs + { + public string From { get; set; } + public IEnumerable Selects { get; set; } = new List(); + public JsonPathArgs() { } + } +} diff --git a/NBi.Core/Hierarchical/Json/JsonPathEngine.cs b/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs similarity index 74% rename from NBi.Core/Hierarchical/Json/JsonPathEngine.cs rename to NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs index 63e3eb4ae..c4f4694e2 100644 --- a/NBi.Core/Hierarchical/Json/JsonPathEngine.cs +++ b/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs @@ -1,29 +1,25 @@ -using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; -using System.Data; using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NBi.Core.Hierarchical; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.ResultSet; using System.Text.RegularExpressions; +using System.Threading.Tasks; -namespace NBi.Core.Hierarchical.Json +namespace NBi.Core.DataSerialization.Flattening.Json { - public abstract class JsonPathEngine : AbstractPathEngine + class JsonPathEngine : PathFlattenizer, IDataSerializationFlattenizer { - protected JsonPathEngine(string from, IEnumerable selects) + public JsonPathEngine(string from, IEnumerable selects) : base(from, selects) { } - public IEnumerable Execute(JToken items) + public override IEnumerable Execute(TextReader textReader) { - var result = from item in items.SelectTokens(From) + var json = JToken.ReadFrom(new JsonTextReader(textReader)); + var result = from item in json.SelectTokens(From) select GetObj(item); - return result; } @@ -34,7 +30,7 @@ private object GetObj(JToken item) return obj; } - protected internal IEnumerable BuildPaths(JToken item, IEnumerable selects) + protected internal IEnumerable BuildPaths(JToken item, IEnumerable selects) { foreach (var select in selects) { @@ -51,7 +47,7 @@ protected internal IEnumerable BuildPaths(JToken item, IEnumerable Selects { get; } + protected string From { get; } + + protected PathFlattenizer(string from, IEnumerable selects) + => (From, Selects) = (from, selects); + + public abstract IEnumerable Execute(TextReader textReader); + } +} diff --git a/NBi.Core/Hierarchical/HierarchicalSelectFactory.cs b/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs similarity index 69% rename from NBi.Core/Hierarchical/HierarchicalSelectFactory.cs rename to NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs index 1603c010b..f1f619fe6 100644 --- a/NBi.Core/Hierarchical/HierarchicalSelectFactory.cs +++ b/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs @@ -4,11 +4,11 @@ using System.Text; using System.Threading.Tasks; -namespace NBi.Core.Hierarchical +namespace NBi.Core.DataSerialization.Flattening { - public class HierarchicalSelectFactory + public class PathFlattenizerFactory { - public AbstractSelect Instantiate(string path, string attribute, bool isEvaluate) + public IPathSelect Instantiate(string path, string attribute, bool isEvaluate) { if (isEvaluate) return new EvaluateSelect(path); diff --git a/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs b/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs new file mode 100644 index 000000000..0048d12dc --- /dev/null +++ b/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs @@ -0,0 +1,19 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Flattening.Xml +{ + public class XPathArgs : IFlattenizerArgs + { + public string From { get; set; } + public IEnumerable Selects { get; set; } = new List(); + public string DefaultNamespacePrefix { get; set; } + public bool IsIgnoreNamespace { get; set; } = false; + + public XPathArgs() { } + } +} diff --git a/NBi.Core/Hierarchical/Xml/XPathEngine.cs b/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs similarity index 77% rename from NBi.Core/Hierarchical/Xml/XPathEngine.cs rename to NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs index 9d47bee45..85f52daf8 100644 --- a/NBi.Core/Hierarchical/Xml/XPathEngine.cs +++ b/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs @@ -8,22 +8,24 @@ using System.Xml; using System.Xml.Linq; using System.Xml.XPath; -using NBi.Core.Hierarchical; +using NBi.Core.DataSerialization; using NBi.Core.ResultSet; -namespace NBi.Core.Hierarchical.Xml +namespace NBi.Core.DataSerialization.Flattening.Xml { - public abstract class XPathEngine : AbstractPathEngine + public class XPathEngine : PathFlattenizer, IDataSerializationFlattenizer { public string DefaultNamespacePrefix { get; } public bool IsIgnoreNamespace { get; } - protected XPathEngine(string from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) + public XPathEngine(string from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) : base(from, selects) => (DefaultNamespacePrefix, IsIgnoreNamespace) = (defaultNamespacePrefix, isIgnoreNamespace); - public IEnumerable Execute(XDocument items) + public override IEnumerable Execute(TextReader textReader) { + var xmlReader = CreateReader(textReader, IsIgnoreNamespace); + var items = XDocument.Load(xmlReader); var nsMgr = new XmlNamespaceManager(new NameTable()); if (!string.IsNullOrEmpty(DefaultNamespacePrefix)) nsMgr.AddNamespace(DefaultNamespacePrefix, items.Root.GetDefaultNamespace().NamespaceName); @@ -46,7 +48,7 @@ private object GetObj(XElement x, IXmlNamespaceResolver ns) return obj; } - protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceResolver ns, IEnumerable selects) + protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceResolver ns, IEnumerable selects) { foreach (var select in selects) if (select is AttributeSelect) @@ -77,16 +79,13 @@ protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceR ).Value; } - protected XmlReader CreateReader(string filePath, bool isRemoveDefaultNamespace) + protected XmlReader CreateReader(TextReader textReader, bool isRemoveDefaultNamespace) { var settings = new XmlReaderSettings(); - var streamReader = GetTextReader(filePath); if (isRemoveDefaultNamespace) - return new XmlIgnoreNamespaceReader(streamReader, settings); + return new XmlIgnoreNamespaceReader(textReader, settings); else - return XmlReader.Create(streamReader, settings); + return XmlReader.Create(textReader, settings); } - - protected abstract TextReader GetTextReader(string filePath); } } diff --git a/NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs b/NBi.Core/DataSerialization/Flattening/Xml/XmlIgnoreNamespaceReader.cs similarity index 89% rename from NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs rename to NBi.Core/DataSerialization/Flattening/Xml/XmlIgnoreNamespaceReader.cs index 80b80ec7f..4fb9b3c8d 100644 --- a/NBi.Core/Hierarchical/Xml/XmlIgnoreNamespaceReader.cs +++ b/NBi.Core/DataSerialization/Flattening/Xml/XmlIgnoreNamespaceReader.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Xml; -namespace NBi.Core.Hierarchical.Xml +namespace NBi.Core.DataSerialization.Flattening.Xml { class XmlIgnoreNamespaceReader : XmlWrappingReader { diff --git a/NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs b/NBi.Core/DataSerialization/Flattening/Xml/XmlWrappingReader.cs similarity index 98% rename from NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs rename to NBi.Core/DataSerialization/Flattening/Xml/XmlWrappingReader.cs index 0c83dc0ac..5423b0d03 100644 --- a/NBi.Core/Hierarchical/Xml/XmlWrappingReader.cs +++ b/NBi.Core/DataSerialization/Flattening/Xml/XmlWrappingReader.cs @@ -6,7 +6,7 @@ using System.Xml; using System.Xml.Schema; -namespace NBi.Core.Hierarchical.Xml +namespace NBi.Core.DataSerialization.Flattening.Xml { class XmlWrappingReader : XmlReader, IXmlLineInfo { diff --git a/NBi.Core/DataSerialization/Reader/DataSerializationReaderFactory.cs b/NBi.Core/DataSerialization/Reader/DataSerializationReaderFactory.cs new file mode 100644 index 000000000..642323f53 --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/DataSerializationReaderFactory.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + class DataSerializationReaderFactory + { + public IDataSerializationReader Instantiate(IReaderArgs args) + { + switch (args) + { + case FileReaderArgs fileArgs: return new FileReader(fileArgs.BasePath, fileArgs.Path); + case UrlReaderArgs urlArgs: return new UrlReader(urlArgs.Url); + case RestReaderArgs restArgs: return new RestReader(restArgs.Rest); + default: throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs b/NBi.Core/DataSerialization/Reader/FileReader.cs similarity index 51% rename from NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs rename to NBi.Core/DataSerialization/Reader/FileReader.cs index 4ecedc5f0..170fc9dae 100644 --- a/NBi.Core/Hierarchical/Json/JsonPathFileEngine.cs +++ b/NBi.Core/DataSerialization/Reader/FileReader.cs @@ -6,29 +6,23 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -namespace NBi.Core.Hierarchical.Json +namespace NBi.Core.DataSerialization.Reader { - public class JsonPathFileEngine : JsonPathEngine + class FileReader : IDataSerializationReader, IDisposable { + private StreamReader StreamReader { get; set; } public string BasePath { get; } public IScalarResolver ResolverPath { get; } - - public JsonPathFileEngine(IScalarResolver resolverPath, string basePath, string from, IEnumerable selects) - : base(from, selects) + + public FileReader( string basePath, IScalarResolver resolverPath) => (BasePath, ResolverPath) = (basePath, resolverPath); - public override IEnumerable Execute() + public TextReader Execute() { var filePath = EnsureFileExist(); - - using (var textReader = GetTextReader(filePath)) - { - var json = JToken.ReadFrom(new JsonTextReader(textReader)); - return Execute(json); - } + StreamReader = new StreamReader(filePath); + return StreamReader; } protected virtual string EnsureFileExist() @@ -39,7 +33,23 @@ protected virtual string EnsureFileExist() return filePath; } - protected virtual TextReader GetTextReader(string filePath) - => new StreamReader(filePath); + bool disposed = false; + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + StreamReader?.Dispose(); + } + disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } } } diff --git a/NBi.Core/DataSerialization/Reader/FileReaderArgs.cs b/NBi.Core/DataSerialization/Reader/FileReaderArgs.cs new file mode 100644 index 000000000..da4446256 --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/FileReaderArgs.cs @@ -0,0 +1,18 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + public class FileReaderArgs : IReaderArgs + { + public string BasePath { get; } + public IScalarResolver Path { get; } + + public FileReaderArgs(string basePath, IScalarResolver path) + => (BasePath, Path) = (basePath, path); + } +} diff --git a/NBi.Core/DataSerialization/Reader/IDataSerializationReader.cs b/NBi.Core/DataSerialization/Reader/IDataSerializationReader.cs new file mode 100644 index 000000000..67355934a --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/IDataSerializationReader.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + public interface IDataSerializationReader : IDisposable + { + TextReader Execute(); + } +} diff --git a/NBi.Core/DataSerialization/Reader/IReaderArgs.cs b/NBi.Core/DataSerialization/Reader/IReaderArgs.cs new file mode 100644 index 000000000..2fd37a7e3 --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/IReaderArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + public interface IReaderArgs + { + + } +} diff --git a/NBi.Core/DataSerialization/Reader/RestReader.cs b/NBi.Core/DataSerialization/Reader/RestReader.cs new file mode 100644 index 000000000..85786d917 --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/RestReader.cs @@ -0,0 +1,47 @@ +using NBi.Core.Api.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + class RestReader : IDataSerializationReader, IDisposable + { + private TextReader TextReader { get; set; } + public RestEngine Rest { get; } + + public RestReader(RestEngine rest) + => (Rest) = (rest); + + public TextReader Execute() + { + TextReader = new StringReader(Rest.Execute()); + return TextReader; + } + + #region "Disposable" + + bool disposed = false; + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + TextReader?.Dispose(); + } + disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/NBi.Core/DataSerialization/Reader/RestReaderArgs.cs b/NBi.Core/DataSerialization/Reader/RestReaderArgs.cs new file mode 100644 index 000000000..29cb70139 --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/RestReaderArgs.cs @@ -0,0 +1,18 @@ +using NBi.Core.Api.Rest; +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + public class RestReaderArgs : IReaderArgs + { + public RestEngine Rest { get; } + + public RestReaderArgs(RestEngine rest) + => (Rest) = (rest); + } +} diff --git a/NBi.Core/DataSerialization/Reader/UrlReader.cs b/NBi.Core/DataSerialization/Reader/UrlReader.cs new file mode 100644 index 000000000..e039a418c --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/UrlReader.cs @@ -0,0 +1,53 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + class UrlReader : IDataSerializationReader, IDisposable + { + + private WebClient WebClient { get; set; } + private MemoryStream Stream { get; set; } + private StreamReader StreamReader { get; set; } + + public IScalarResolver UrlResolver { get; } + + public UrlReader(IScalarResolver urlResolver) + => UrlResolver = urlResolver; + + public TextReader Execute() + { + WebClient = new WebClient(); + Stream = new MemoryStream(WebClient.DownloadData(UrlResolver.Execute())); + StreamReader = new StreamReader(Stream); + return StreamReader; + } + + bool disposed = false; + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + StreamReader?.Dispose(); + Stream?.Dispose(); + WebClient.Dispose(); + } + disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/NBi.Core/DataSerialization/Reader/UrlReaderArgs.cs b/NBi.Core/DataSerialization/Reader/UrlReaderArgs.cs new file mode 100644 index 000000000..a69ccc37b --- /dev/null +++ b/NBi.Core/DataSerialization/Reader/UrlReaderArgs.cs @@ -0,0 +1,17 @@ +using NBi.Core.Scalar.Resolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Core.DataSerialization.Reader +{ + public class UrlReaderArgs : IReaderArgs + { + public IScalarResolver Url { get; } + + public UrlReaderArgs(IScalarResolver url) + => (Url) = (url); + } +} diff --git a/NBi.Core/Hierarchical/AbstractPathEngine.cs b/NBi.Core/Hierarchical/AbstractPathEngine.cs deleted file mode 100644 index 37746c447..000000000 --- a/NBi.Core/Hierarchical/AbstractPathEngine.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using NBi.Core.Hierarchical; -using NBi.Core.ResultSet; - -namespace NBi.Core.Hierarchical -{ - public abstract class AbstractPathEngine - { - protected IEnumerable Selects { get; } - protected string From { get; } - - public AbstractPathEngine(string from, IEnumerable selects) - => (From, Selects) = (from, selects); - - public abstract IEnumerable Execute(); - } -} diff --git a/NBi.Core/Hierarchical/ElementSelect.cs b/NBi.Core/Hierarchical/ElementSelect.cs deleted file mode 100644 index 9aa03ec51..000000000 --- a/NBi.Core/Hierarchical/ElementSelect.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NBi.Core.Hierarchical -{ - public class ElementSelect : AbstractSelect - { - internal ElementSelect(string path) - : base(path) { } - } -} diff --git a/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs deleted file mode 100644 index 86c5a1670..000000000 --- a/NBi.Core/Hierarchical/Json/JsonPathRestEngine.cs +++ /dev/null @@ -1,31 +0,0 @@ -using NBi.Core.Scalar.Resolver; -using NBi.Extensibility; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Net; -using NBi.Core.Api.Rest; - -namespace NBi.Core.Hierarchical.Json -{ - public class JsonPathRestEngine : JsonPathEngine - { - public RestEngine Rest { get; } - - public JsonPathRestEngine(RestEngine rest, string from, IEnumerable selects) - : base(from, selects) - => (Rest) = (rest); - - public override IEnumerable Execute() - { - var jsonText = Rest.Execute(); - var json = JToken.Parse(jsonText); - return Execute(json); - } - } -} diff --git a/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs b/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs deleted file mode 100644 index 4e21e3e4a..000000000 --- a/NBi.Core/Hierarchical/Json/JsonPathUrlEngine.cs +++ /dev/null @@ -1,37 +0,0 @@ -using NBi.Core.Scalar.Resolver; -using NBi.Extensibility; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Net; - -namespace NBi.Core.Hierarchical.Json -{ - public class JsonPathUrlEngine : JsonPathEngine - { - public IScalarResolver Url { get; } - - public JsonPathUrlEngine(IScalarResolver url, string from, IEnumerable selects) - : base(from, selects) - => (Url) = (url); - - public override IEnumerable Execute() - { - var url = Url.Execute(); - var jsonText = GetRemoteContent(url); - var json = JToken.Parse(jsonText); - return Execute(json); - } - - protected virtual string GetRemoteContent(string url) - { - using (var webClient = new WebClient()) - return webClient.DownloadString(url); - } - } -} diff --git a/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs b/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs deleted file mode 100644 index 3ffd7afe7..000000000 --- a/NBi.Core/Hierarchical/Xml/XPathFileEngine.cs +++ /dev/null @@ -1,45 +0,0 @@ -using NBi.Core.Scalar.Resolver; -using NBi.Extensibility; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Linq; - -namespace NBi.Core.Hierarchical.Xml -{ - public class XPathFileEngine : XPathEngine - { - public string BasePath { get; } - public IScalarResolver ResolverPath { get; } - - public XPathFileEngine(IScalarResolver resolverPath, string basePath, string from, IEnumerable selects, string defaultNamespacePrefix, bool isRemoveDefaultNamespace) - : base(from, selects, defaultNamespacePrefix, isRemoveDefaultNamespace) - => (BasePath, ResolverPath) = (basePath, resolverPath); - - public override IEnumerable Execute() - { - var filePath = EnsureFileExist(); - - using (var xmlreader = CreateReader(filePath, IsIgnoreNamespace)) - { - var doc = XDocument.Load(xmlreader); - return Execute(doc); - } - } - - protected virtual string EnsureFileExist() - { - var filePath = PathExtensions.CombineOrRoot(BasePath, string.Empty, ResolverPath.Execute()); - if (!File.Exists(filePath)) - throw new ExternalDependencyNotFoundException(filePath); - return filePath; - } - - protected override TextReader GetTextReader(string filePath) - => new StreamReader(filePath); - } -} diff --git a/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs b/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs deleted file mode 100644 index b707ecf85..000000000 --- a/NBi.Core/Hierarchical/Xml/XPathRestEngine.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NBi.Core.Api.Rest; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace NBi.Core.Hierarchical.Xml -{ - public class XPathRestEngine : XPathEngine - { - public RestEngine Rest { get; } - - public XPathRestEngine(RestEngine rest, string from, IEnumerable selects, string defaultNamespacePrefix) - : base(from, selects, defaultNamespacePrefix, false) - => Rest = rest; - - public override IEnumerable Execute() - { - var xmlText = Rest.Execute(); - using (var xmlreader = CreateReader(xmlText, IsIgnoreNamespace)) - { - var doc = XDocument.Load(xmlreader); - return Execute(doc); - } - } - - protected override TextReader GetTextReader(string text) - => new StringReader(text); - } -} diff --git a/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs b/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs deleted file mode 100644 index 0b99a639f..000000000 --- a/NBi.Core/Hierarchical/Xml/XPathUrlEngine.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace NBi.Core.Hierarchical.Xml -{ - public class XPathUrlEngine : XPathEngine - { - public string Url { get; private set; } - - public XPathUrlEngine(string url, string from, IEnumerable selects, string defaultNamespacePrefix) - : base(from, selects, defaultNamespacePrefix, false) - => Url = url; - - public override IEnumerable Execute() - { - var doc = XDocument.Load(Url); - return Execute(doc); - } - - protected override TextReader GetTextReader(string filePath) - => throw new NotImplementedException(); - } -} diff --git a/NBi.Core/NBi.Core.csproj b/NBi.Core/NBi.Core.csproj index 40144ae39..952e83925 100644 --- a/NBi.Core/NBi.Core.csproj +++ b/NBi.Core/NBi.Core.csproj @@ -149,6 +149,24 @@ + + + + + + + + + + + + + + + + + + @@ -280,12 +298,7 @@ - - - - - - + @@ -578,7 +591,7 @@ - + @@ -601,7 +614,7 @@ - + @@ -886,16 +899,14 @@ - - - - - - - - - - + + + + + + + + diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs b/NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolver.cs similarity index 60% rename from NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs rename to NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolver.cs index 6198917c6..a94116e0d 100644 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolver.cs +++ b/NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolver.cs @@ -1,5 +1,5 @@ using NBi.Core.Query; -using NBi.Core.Hierarchical.Xml; +using NBi.Core.DataSerialization; using System; using System.Collections.Generic; using System.Data; @@ -10,18 +10,20 @@ namespace NBi.Core.ResultSet.Resolver { - class XPathResultSetResolver : IResultSetResolver + class DataSerializationResultSetResolver : IResultSetResolver { - private XPathResultSetResolverArgs Args { get; } + private DataSerializationResultSetResolverArgs Args { get; } - public XPathResultSetResolver(XPathResultSetResolverArgs args) + public DataSerializationResultSetResolver(DataSerializationResultSetResolverArgs args) => Args = args; public virtual ResultSet Execute() { try - { - var objects = Args.XPathEngine.Execute(); + { + var factory = new DataSerializationProcessorFactory(); + var processor = factory.Instantiate(Args); + var objects = processor.Execute(); var helper = new ObjectsToRowsHelper(); var rows = helper.Execute(objects); @@ -36,4 +38,5 @@ public virtual ResultSet Execute() } } } + } diff --git a/NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolverArgs.cs new file mode 100644 index 000000000..f0e50e9c7 --- /dev/null +++ b/NBi.Core/ResultSet/Resolver/DataSerializationResultSetResolverArgs.cs @@ -0,0 +1,22 @@ +using NBi.Core.Query; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NBi.Core.DataSerialization; +using NBi.Core.DataSerialization.Reader; +using NBi.Core.DataSerialization.Flattening; + +namespace NBi.Core.ResultSet.Resolver +{ + public class DataSerializationResultSetResolverArgs : ResultSetResolverArgs + { + public IReaderArgs Reader { get; } + public IFlattenizerArgs Flattenizer { get; } + + public DataSerializationResultSetResolverArgs(IReaderArgs reader, IFlattenizerArgs flattenizer) + => (Reader, Flattenizer) = (reader, flattenizer); + } +} diff --git a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs index 8d44eeb47..19baf3906 100644 --- a/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs +++ b/NBi.Core/ResultSet/Resolver/ResultSetResolverFactory.cs @@ -2,9 +2,6 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using NBi.Core.Query; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Query.Resolver; using NBi.Core.Injection; using NBi.Core.FlatFile; @@ -34,7 +31,7 @@ public IResultSetResolver Instantiate(ResultSetResolverArgs args) case RowsResultSetResolverArgs x: return new RowsResultSetResolver(x); case QueryResultSetResolverArgs x: return new QueryResultSetResolver(x, serviceLocator); case FlatFileResultSetResolverArgs x: return new FlatFileResultSetResolver(x, serviceLocator); - case XPathResultSetResolverArgs x: return new XPathResultSetResolver(x); + case DataSerializationResultSetResolverArgs x: return new DataSerializationResultSetResolver(x); case ObjectsResultSetResolverArgs x: return new ObjectsResultSetResolver(x); case SequenceCombinationResultSetResolverArgs x: return new SequenceCombinationResultSetResolver(x); case EmptyResultSetResolverArgs x: return new EmptyResultSetResolver(x); diff --git a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs b/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs deleted file mode 100644 index a3827a11c..000000000 --- a/NBi.Core/ResultSet/Resolver/XPathResultSetResolverArgs.cs +++ /dev/null @@ -1,20 +0,0 @@ -using NBi.Core.Query; -using NBi.Core.Hierarchical.Xml; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using NBi.Core.Hierarchical; - -namespace NBi.Core.ResultSet.Resolver -{ - public class XPathResultSetResolverArgs : ResultSetResolverArgs - { - public AbstractPathEngine XPathEngine { get; } - - public XPathResultSetResolverArgs(AbstractPathEngine xpathEngine) - => XPathEngine = xpathEngine; - } -} diff --git a/NBi.Core/ResultSet/ResultSetServiceBuilder.cs b/NBi.Core/ResultSet/ResultSetServiceBuilder.cs index 917ed4b92..aa0f3870f 100644 --- a/NBi.Core/ResultSet/ResultSetServiceBuilder.cs +++ b/NBi.Core/ResultSet/ResultSetServiceBuilder.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using NBi.Core.Query; -using NBi.Core.Hierarchical.Xml; using NBi.Core.ResultSet.Resolver; -using NBi.Core.Transformation; using NBi.Core.ResultSet.Alteration; namespace NBi.Core.ResultSet diff --git a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs index 5bfd1d117..041d8881a 100644 --- a/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs +++ b/NBi.Core/Scalar/Resolver/ScalarResolverFactory.cs @@ -2,9 +2,6 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using NBi.Core.Query; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Query.Resolver; using NBi.Core.Injection; using System.Reflection; diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 27c3d4391..3371d065b 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -3,8 +3,7 @@ using NBi.Core.ResultSet.Resolver; using NBi.Core.Sequence.Resolver; using NBi.Core.Variable; -using NBi.Core.Hierarchical; -using NBi.Core.Hierarchical.Xml; +using NBi.Core.DataSerialization; using NBi.Xml.Items; using NBi.Xml.Items.ResultSet; using NBi.Xml.Items.ResultSet.Combination; @@ -20,11 +19,14 @@ using System.Text; using System.Threading.Tasks; using NBi.Xml.Items.Hierarchical.Json; -using NBi.Core.Hierarchical.Json; using NBi.Core.Api.Rest; using NBi.Core.Api.Authentication; using NBi.Xml.Items.Api.Rest; using NBi.Xml.Items.Api.Authentication; +using NBi.Core.DataSerialization.Flattening; +using NBi.Core.DataSerialization.Flattening.Xml; +using NBi.Core.DataSerialization.Reader; +using NBi.Core.DataSerialization.Flattening.Json; namespace NBi.NUnit.Builder.Helper { @@ -200,60 +202,73 @@ private ResultSetResolverArgs BuildFlatFileResultSetResolverArgs(FileXml fileMet private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) { Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceVerbose, "ResultSet defined through an xml-source."); - - var selects = new List(); - var selectFactory = new HierarchicalSelectFactory(); - foreach (var select in xmlSource.XPath.Selects) - selects.Add(selectFactory.Instantiate(select.Value, select.Attribute, select.Evaluate)); - var helper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); - XPathEngine engine = null; + IReaderArgs reader = null; if (xmlSource.File != null) { var resolverPath = helper.InstantiateResolver(xmlSource.File.Path); - engine = new XPathFileEngine(resolverPath, settings?.BasePath, xmlSource.XPath.From.Value, selects, xmlSource.XPath?.DefaultNamespacePrefix, xmlSource.IgnoreNamespace); + reader = new FileReaderArgs(settings?.BasePath, resolverPath); } else if (xmlSource.Url != null) - engine = new XPathUrlEngine(xmlSource.Url.Value, xmlSource.XPath.From.Value, selects, xmlSource.XPath?.DefaultNamespacePrefix); + { + var resolverUrl = helper.InstantiateResolver(xmlSource.Url.Value); + reader = new UrlReaderArgs(resolverUrl); + } else if (xmlSource.Rest != null) { var restHelper = new RestHelper(ServiceLocator, settings, scope, Variables); - engine = new XPathRestEngine(restHelper.Execute(xmlSource.Rest), xmlSource.XPath.From.Value, selects, xmlSource.XPath?.DefaultNamespacePrefix); + reader = new RestReaderArgs(restHelper.Execute(xmlSource.Rest)); } - return new XPathResultSetResolverArgs(engine); + + var selects = new List(); + var selectFactory = new PathFlattenizerFactory(); + foreach (var select in xmlSource.XPath.Selects) + selects.Add(selectFactory.Instantiate(select.Value, select.Attribute, select.Evaluate)); + var flattenizer = new XPathArgs + { + From = xmlSource.XPath.From.Value, + Selects = selects, + DefaultNamespacePrefix = xmlSource.XPath?.DefaultNamespacePrefix, + IsIgnoreNamespace = xmlSource.IgnoreNamespace + }; + + return new DataSerializationResultSetResolverArgs(reader, flattenizer); } private ResultSetResolverArgs BuildJsonPathResolverArgs(JsonSourceXml jsonSource) { Trace.WriteLineIf(Extensibility.NBiTraceSwitch.TraceVerbose, "ResultSet defined through an json-source."); - - var selects = new List(); - var selectFactory = new HierarchicalSelectFactory(); - foreach (var select in jsonSource.JsonPath.Selects) - selects.Add(selectFactory.Instantiate(select.Value, null, false)); - var helper = new ScalarHelper(ServiceLocator, settings, scope, new Context(Variables)); - - JsonPathEngine engine = null; + IReaderArgs reader = null; if (jsonSource.File != null) { var resolverPath = helper.InstantiateResolver(jsonSource.File.Path); - engine = new JsonPathFileEngine(resolverPath, settings?.BasePath, jsonSource.JsonPath.From.Value, selects); + reader = new FileReaderArgs(settings?.BasePath, resolverPath); } else if (jsonSource.Url != null) { var resolverUrl = helper.InstantiateResolver(jsonSource.Url.Value); - engine = new JsonPathUrlEngine(resolverUrl, jsonSource.JsonPath.From.Value, selects); + reader = new UrlReaderArgs(resolverUrl); } else if (jsonSource.Rest != null) { var restHelper = new RestHelper(ServiceLocator, settings, scope, Variables); - engine = new JsonPathRestEngine(restHelper.Execute(jsonSource.Rest), jsonSource.JsonPath.From.Value, selects); + reader = new RestReaderArgs(restHelper.Execute(jsonSource.Rest)); } - return new XPathResultSetResolverArgs(engine); + var selects = new List(); + var selectFactory = new PathFlattenizerFactory(); + foreach (var select in jsonSource.JsonPath.Selects) + selects.Add(selectFactory.Instantiate(select.Value, string.Empty, false)); + var flattenizer = new JsonPathArgs + { + From = jsonSource.JsonPath.From.Value, + Selects = selects, + }; + + return new DataSerializationResultSetResolverArgs(reader, flattenizer); } private ResultSetResolverArgs BuildEmptyResolverArgs(EmptyResultSetXml empty) diff --git a/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs b/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs index 7ee694154..dc9ae4ab1 100644 --- a/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetEqualToBuilder.cs @@ -1,21 +1,12 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using NBi.Core; -using NBi.Core.Query; using NBi.Core.ResultSet; -using NBi.Core.Scalar.Comparer; using NBi.NUnit.ResultSetComparison; using NBi.Xml.Constraints; using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Hierarchical.Xml; using NBi.Core.Transformation; -using System.Data; -using NBi.Core.ResultSet.Resolver; -using System.IO; -using NBi.Core.Query.Resolver; using NBi.Core.ResultSet.Equivalence; using NBi.NUnit.Builder.Helper; using NBi.Xml.Settings; diff --git a/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs b/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs index 3077f9272..5406f72d8 100644 --- a/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs +++ b/NBi.NUnit/Builder/ResultSetSubsetOfBuilder.cs @@ -1,22 +1,9 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using NBi.Core; using NBi.Core.ResultSet; -using NBi.Core.Scalar.Comparer; -using NBi.NUnit.Query; using NBi.Xml.Constraints; -using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Transformation; using NBi.NUnit.ResultSetComparison; -using System.Data; -using NBi.Core.ResultSet.Resolver; using NBi.Core.ResultSet.Equivalence; -using NBi.NUnit.Builder.Helper; -using NBi.Xml.Settings; namespace NBi.NUnit.Builder { diff --git a/NBi.NUnit/Builder/ScalarScoreBuilder.cs b/NBi.NUnit/Builder/ScalarScoreBuilder.cs index c79998b4b..647a0a079 100644 --- a/NBi.NUnit/Builder/ScalarScoreBuilder.cs +++ b/NBi.NUnit/Builder/ScalarScoreBuilder.cs @@ -1,24 +1,6 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using NBi.Core; -using NBi.Core.Query; -using NBi.Core.ResultSet; -using NBi.Core.Scalar.Comparer; -using NBi.NUnit.ResultSetComparison; using NBi.Xml.Constraints; -using NBi.Xml.Items; using NBi.Xml.Systems; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Transformation; -using System.Data; -using NBi.Core.ResultSet.Resolver; -using System.IO; -using NBi.Core.Query.Resolver; -using NBi.Core.ResultSet.Equivalence; -using NBi.NUnit.Builder.Helper; -using NBi.Xml.Settings; using NBi.NUnit.Scoring; namespace NBi.NUnit.Builder diff --git a/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs b/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs index 1ce31c0b3..b918ea69e 100644 --- a/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs +++ b/NBi.NUnit/ResultSetComparison/BaseResultSetComparisonConstraint.cs @@ -1,18 +1,11 @@ using System; -using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; -using NBi.Core; using NBi.Core.ResultSet; using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework.FailureMessage; -using NBi.Framework; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Transformation; using NBi.Core.ResultSet.Analyzer; -using NBi.Core.ResultSet.Resolver; -using NBi.Framework.FailureMessage.Markdown; using NBi.Core.ResultSet.Equivalence; using NUnit.Framework; using NBi.Core.Configuration.FailureReport; diff --git a/NBi.NUnit/Scoring/ScoreConstraint.cs b/NBi.NUnit/Scoring/ScoreConstraint.cs index 9f798f53b..29d2f72d6 100644 --- a/NBi.NUnit/Scoring/ScoreConstraint.cs +++ b/NBi.NUnit/Scoring/ScoreConstraint.cs @@ -1,19 +1,6 @@ using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Linq; -using NBi.Core; -using NBi.Core.ResultSet; using NUnitCtr = NUnit.Framework.Constraints; using NBi.Framework.FailureMessage; -using NBi.Framework; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Transformation; -using NBi.Core.ResultSet.Analyzer; -using NBi.Core.ResultSet.Resolver; -using NBi.Framework.FailureMessage.Markdown; -using NBi.Core.ResultSet.Equivalence; using NUnit.Framework; using NBi.Core.Configuration.FailureReport; using NBi.Core.Scalar.Resolver; diff --git a/NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs b/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs similarity index 77% rename from NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs rename to NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs index 2203660f2..2e48a0442 100644 --- a/NBi.Testing.Core/Hierarchical/Json/JsonPathFileEngineTest.cs +++ b/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs @@ -1,6 +1,5 @@ -using NBi.Core.Hierarchical; -using NBi.Core.Hierarchical.Json; -using NBi.Core.Scalar.Resolver; +using NBi.Core.DataSerialization.Flattening; +using NBi.Core.DataSerialization.Flattening.Json; using NUnit.Framework; using System; using System.Collections.Generic; @@ -11,25 +10,10 @@ using System.Threading.Tasks; using System.Xml.Linq; -namespace NBi.Testing.Core.Hierarchical.Json +namespace NBi.Testing.Core.DataSerialization.Flattenizer { - public class JsonPathFileEngineTest + public class JsonPathEngineTest { - private class JsonPathStreamEngine : JsonPathFileEngine - { - private StreamReader StreamReader { get; } - - protected internal JsonPathStreamEngine(StreamReader streamReader, string from, IEnumerable selects) - : base(new LiteralScalarResolver(string.Empty), string.Empty, from, selects) - => StreamReader = streamReader; - - protected override TextReader GetTextReader(string filePath) - => StreamReader; - - protected override string EnsureFileExist() - => string.Empty; - } - protected StreamReader GetResourceReader(string filename) { // A Stream is needed to read the XML document. @@ -52,8 +36,8 @@ public void Execute_Example_RowCount(string from, int rowCount) using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(rowCount)); } } @@ -69,8 +53,8 @@ public void Execute_Example_FirstColumnIsCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(5)); Assert.That(result.Select(x => ((x as IEnumerable).ElementAt(0) as string).Length), Is.All.EqualTo(6)); //Format is 123-XY } @@ -88,8 +72,8 @@ public void Execute_Example_AllColumnsAreCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(5)); Assert.That(result.Count, Is.EqualTo(5)); Assert.That(result.Select(x => ((x as IEnumerable).ElementAt(0) as string).Length), Is.All.EqualTo(6)); //Format is 123-XY @@ -109,8 +93,8 @@ public void Execute_FromElement_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } } @@ -126,8 +110,8 @@ public void Execute_FromAttribute_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } } @@ -143,8 +127,8 @@ public void Execute_MissingElement_Null() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That((result.ElementAt(3) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } } @@ -161,8 +145,8 @@ public void Execute_ParentElement_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("99503")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); @@ -186,8 +170,8 @@ public void Execute_ParentElementGoingAboveRoot_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new JsonPathEngine(from, selects); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("(null)")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); diff --git a/NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json b/NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrders.json similarity index 100% rename from NBi.Testing.Core/Hierarchical/Json/Resources/PurchaseOrders.json rename to NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrders.json diff --git a/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrders.xml b/NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrders.xml similarity index 100% rename from NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrders.xml rename to NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrders.xml diff --git a/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersDefaultNamespace.xml b/NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrdersDefaultNamespace.xml similarity index 100% rename from NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersDefaultNamespace.xml rename to NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrdersDefaultNamespace.xml diff --git a/NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersManyNamespaces.xml b/NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrdersManyNamespaces.xml similarity index 100% rename from NBi.Testing.Core/Hierarchical/Xml/Resources/PurchaseOrdersManyNamespaces.xml rename to NBi.Testing.Core/DataSerialization/Flattenizer/Resources/PurchaseOrdersManyNamespaces.xml diff --git a/NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs b/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs similarity index 71% rename from NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs rename to NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs index 64d60e112..0bd7c5319 100644 --- a/NBi.Testing.Core/Hierarchical/Xml/XPathEngineTest.cs +++ b/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs @@ -1,6 +1,5 @@ -using NBi.Core.Hierarchical; -using NBi.Core.Hierarchical.Xml; -using NBi.Core.Scalar.Resolver; +using NBi.Core.DataSerialization.Flattening; +using NBi.Core.DataSerialization.Flattening.Xml; using NUnit.Framework; using System; using System.Collections.Generic; @@ -11,41 +10,10 @@ using System.Threading.Tasks; using System.Xml.Linq; -namespace NBi.Testing.Core.Hierarchical.Xml +namespace NBi.Testing.Core.DataSerialization.Flattenizer { public class XPathStreamEngineTest { - private class XPathStreamEngine : XPathFileEngine - { - private readonly StreamReader streamReader; - - public XPathStreamEngine(StreamReader streamReader, string from, IEnumerable selects) - : this(streamReader, from, selects, string.Empty, false) - { } - - public XPathStreamEngine(StreamReader streamReader, string from, IEnumerable selects, string prefix) - : this(streamReader, from, selects, prefix, false) - { } - - protected XPathStreamEngine(StreamReader streamReader, string from, IEnumerable selects, string prefix, bool ignoreDefaultNamespace) - : base(new LiteralScalarResolver(string.Empty), string.Empty, from, selects, prefix, ignoreDefaultNamespace) - => this.streamReader = streamReader; - - protected override TextReader GetTextReader(string filePath) - => streamReader; - - protected override string EnsureFileExist() - => string.Empty; - } - - private class XPathStreamIgnoreNamespaceEngine : XPathStreamEngine - { - public XPathStreamIgnoreNamespaceEngine(StreamReader streamReader, string from, IEnumerable selects, string prefix) - : base(streamReader, from, selects, prefix, true) - { } - } - - protected StreamReader GetResourceReader(string filename) { // A Stream is needed to read the XML document. @@ -68,8 +36,8 @@ public void Execute_Example_ColumnCount() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).Count, Is.EqualTo(3)); } } @@ -88,8 +56,8 @@ public void Execute_Example_RowCount(string from, int rowCount) using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(rowCount)); } } @@ -105,8 +73,8 @@ public void Execute_FromElement_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } } @@ -122,8 +90,8 @@ public void Execute_FromAttribute_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } } @@ -139,8 +107,8 @@ public void Execute_ChildElement_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } } @@ -156,8 +124,8 @@ public void Execute_ChildAttribute_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } } @@ -173,8 +141,8 @@ public void Execute_ParentElement_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("Ellen Adams")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("Maple Street")); } @@ -191,8 +159,8 @@ public void Execute_ParentAttribute_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("99503")); } } @@ -208,8 +176,8 @@ public void Execute_MissingElement_Null() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } } @@ -225,8 +193,8 @@ public void Execute_MissingAttribute_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathStreamEngine(reader, from, selects); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, string.Empty, false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } } @@ -242,8 +210,8 @@ public void Execute_FromElementWithDefaultNamespace_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrdersDefaultNamespace")) { - var engine = new XPathStreamEngine(reader, from, selects, "prefix"); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, "prefix", false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } } @@ -259,8 +227,8 @@ public void Execute_FromElementWithDefaultNamespaceAndIgnoreDefaultNamespace_Val using (var reader = GetResourceReader("PurchaseOrdersDefaultNamespace")) { - var engine = new XPathStreamIgnoreNamespaceEngine(reader, from, selects, "prefix"); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, "prefix", true); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } } @@ -276,8 +244,8 @@ public void Execute_FromElementWithManyNamespaces_ValueCorrect() using (var reader = GetResourceReader("PurchaseOrdersManyNamespaces")) { - var engine = new XPathStreamEngine(reader, from, selects, "prefix"); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, "prefix", false); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("123 Maple Street")); } } @@ -293,8 +261,8 @@ public void Execute_FromElementWithManyNamespacesIgnoringDefaultNamespace_ValueC using (var reader = GetResourceReader("PurchaseOrdersManyNamespaces")) { - var engine = new XPathStreamIgnoreNamespaceEngine(reader, from, selects, "prefix"); - var result = engine.Execute(); + var engine = new XPathEngine(from, selects, "prefix", true); + var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("123 Maple Street")); } } diff --git a/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs b/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs deleted file mode 100644 index 1d02f78d0..000000000 --- a/NBi.Testing.Core/Hierarchical/Json/JsonPathUrlEngineTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -using NBi.Core.Hierarchical; -using NBi.Core.Hierarchical.Json; -using NBi.Core.Scalar.Resolver; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace NBi.Testing.Core.Hierarchical.Json -{ - public class JsonPathUrlEngineTest - { - private class StubJsonPathUrlEngine : JsonPathUrlEngine - { - public StubJsonPathUrlEngine(IScalarResolver url, string from, IEnumerable selects) - : base(url, from, selects) { } - - protected override string GetRemoteContent(string url) - { - using (var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"{GetType().Namespace}.Resources.{url}")) - using (var streamReader = new StreamReader(stream)) - return streamReader.ReadToEnd(); - } - } - - [Test] - [TestCase("$.PurchaseOrders[*].Items[*]", 5)] - [TestCase("$.PurchaseOrders[*]", 4)] - public void Execute_Example_RowCount(string from, int rowCount) - { - var selects = new List() - { - new ElementSelect("$") - }; - - var engine = new StubJsonPathUrlEngine(new LiteralScalarResolver("PurchaseOrders.json"), from, selects); - var result = engine.Execute(); - Assert.That(result.Count, Is.EqualTo(rowCount)); - } - } -} diff --git a/NBi.Testing.Core/NBi.Testing.Core.csproj b/NBi.Testing.Core/NBi.Testing.Core.csproj index ee82c34d9..98374c6e5 100644 --- a/NBi.Testing.Core/NBi.Testing.Core.csproj +++ b/NBi.Testing.Core/NBi.Testing.Core.csproj @@ -132,8 +132,7 @@ - - + @@ -279,7 +278,7 @@ - + @@ -316,7 +315,7 @@ - + @@ -337,13 +336,13 @@ - + - + - + From 14a7b1f3dea9c72044b520f73814c41412c9f8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 14 Jan 2020 23:49:27 +0100 Subject: [PATCH 54/57] Implement support of ScalarResolver everywhere --- .../Flattening/AttributeSelect.cs | 5 +- .../Flattening/ElementSelect.cs | 7 +- .../Flattening/EvaluateSelect.cs | 5 +- .../Flattening/IFlattenizerArgs.cs | 4 +- .../Flattening/IPathSelect.cs | 5 +- .../Flattening/Json/JsonPathArgs.cs | 2 +- .../Flattening/Json/JsonPathEngine.cs | 9 ++- .../Flattening/PathFlattenizer.cs | 5 +- .../Flattening/PathFlattenizerFactory.cs | 5 +- .../Flattening/Xml/XPathArgs.cs | 2 +- .../Flattening/Xml/XPathEngine.cs | 11 +-- .../Helper/ResultSetResolverArgsBuilder.cs | 8 +- .../Flattenizer/JsonPathEngineTest.cs | 39 +++++----- .../Flattenizer/XPathEngineTest.cs | 65 ++++++++-------- .../Positive/ResultSetConstraint.nbits | 74 +++++++++++++++++++ 15 files changed, 166 insertions(+), 80 deletions(-) diff --git a/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs b/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs index c469f7d87..6fb71b6b9 100644 --- a/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/AttributeSelect.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,7 +11,7 @@ public class AttributeSelect: ElementSelect { public string Attribute { get; } - internal AttributeSelect(string path, string attribute) + internal AttributeSelect(IScalarResolver path, string attribute) : base(path) => Attribute = attribute; } diff --git a/NBi.Core/DataSerialization/Flattening/ElementSelect.cs b/NBi.Core/DataSerialization/Flattening/ElementSelect.cs index 211c997a5..b2353dfdd 100644 --- a/NBi.Core/DataSerialization/Flattening/ElementSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/ElementSelect.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,9 +9,9 @@ namespace NBi.Core.DataSerialization.Flattening { public class ElementSelect : IPathSelect { - public string Path { get; } + public IScalarResolver Path { get; } - internal ElementSelect(string path) + internal ElementSelect(IScalarResolver path) => Path = path; } } diff --git a/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs b/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs index 883793047..517c8d83e 100644 --- a/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/EvaluateSelect.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,7 +9,7 @@ namespace NBi.Core.DataSerialization.Flattening { public class EvaluateSelect: ElementSelect { - internal EvaluateSelect(string path) + internal EvaluateSelect(IScalarResolver path) : base(path) { } } } diff --git a/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs b/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs index ab85543cf..f23653335 100644 --- a/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs +++ b/NBi.Core/DataSerialization/Flattening/IFlattenizerArgs.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,6 +9,7 @@ namespace NBi.Core.DataSerialization.Flattening { public interface IFlattenizerArgs { + IScalarResolver From { get; } IEnumerable Selects { get; } } } diff --git a/NBi.Core/DataSerialization/Flattening/IPathSelect.cs b/NBi.Core/DataSerialization/Flattening/IPathSelect.cs index 9889c3cb7..0379e6e21 100644 --- a/NBi.Core/DataSerialization/Flattening/IPathSelect.cs +++ b/NBi.Core/DataSerialization/Flattening/IPathSelect.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,6 +9,6 @@ namespace NBi.Core.DataSerialization.Flattening { public interface IPathSelect { - string Path { get; } + IScalarResolver Path { get; } } } diff --git a/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs b/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs index 728de6b6c..994c1c246 100644 --- a/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs +++ b/NBi.Core/DataSerialization/Flattening/Json/JsonPathArgs.cs @@ -9,7 +9,7 @@ namespace NBi.Core.DataSerialization.Flattening.Json { public class JsonPathArgs : IFlattenizerArgs { - public string From { get; set; } + public IScalarResolver From { get; set; } public IEnumerable Selects { get; set; } = new List(); public JsonPathArgs() { } } diff --git a/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs b/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs index c4f4694e2..b5f17d29c 100644 --- a/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs +++ b/NBi.Core/DataSerialization/Flattening/Json/JsonPathEngine.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using NBi.Core.Scalar.Resolver; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -12,13 +13,13 @@ namespace NBi.Core.DataSerialization.Flattening.Json { class JsonPathEngine : PathFlattenizer, IDataSerializationFlattenizer { - public JsonPathEngine(string from, IEnumerable selects) + public JsonPathEngine(IScalarResolver from, IEnumerable selects) : base(from, selects) { } public override IEnumerable Execute(TextReader textReader) { var json = JToken.ReadFrom(new JsonTextReader(textReader)); - var result = from item in json.SelectTokens(From) + var result = from item in json.SelectTokens(From.Execute()) select GetObj(item); return result; } @@ -34,7 +35,7 @@ protected internal IEnumerable BuildPaths(JToken item, IEnumerable Selects { get; } - protected string From { get; } + protected IScalarResolver From { get; } - protected PathFlattenizer(string from, IEnumerable selects) + protected PathFlattenizer(IScalarResolver from, IEnumerable selects) => (From, Selects) = (from, selects); public abstract IEnumerable Execute(TextReader textReader); diff --git a/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs b/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs index f1f619fe6..7b475d655 100644 --- a/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs +++ b/NBi.Core/DataSerialization/Flattening/PathFlattenizerFactory.cs @@ -1,4 +1,5 @@ -using System; +using NBi.Core.Scalar.Resolver; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,7 +9,7 @@ namespace NBi.Core.DataSerialization.Flattening { public class PathFlattenizerFactory { - public IPathSelect Instantiate(string path, string attribute, bool isEvaluate) + public IPathSelect Instantiate(IScalarResolver path, string attribute, bool isEvaluate) { if (isEvaluate) return new EvaluateSelect(path); diff --git a/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs b/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs index 0048d12dc..0ecab9ec4 100644 --- a/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs +++ b/NBi.Core/DataSerialization/Flattening/Xml/XPathArgs.cs @@ -9,7 +9,7 @@ namespace NBi.Core.DataSerialization.Flattening.Xml { public class XPathArgs : IFlattenizerArgs { - public string From { get; set; } + public IScalarResolver From { get; set; } public IEnumerable Selects { get; set; } = new List(); public string DefaultNamespacePrefix { get; set; } public bool IsIgnoreNamespace { get; set; } = false; diff --git a/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs b/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs index 85f52daf8..29a1ab0c4 100644 --- a/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs +++ b/NBi.Core/DataSerialization/Flattening/Xml/XPathEngine.cs @@ -10,6 +10,7 @@ using System.Xml.XPath; using NBi.Core.DataSerialization; using NBi.Core.ResultSet; +using NBi.Core.Scalar.Resolver; namespace NBi.Core.DataSerialization.Flattening.Xml { @@ -18,7 +19,7 @@ public class XPathEngine : PathFlattenizer, IDataSerializationFlattenizer public string DefaultNamespacePrefix { get; } public bool IsIgnoreNamespace { get; } - public XPathEngine(string from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) + public XPathEngine(IScalarResolver from, IEnumerable selects, string defaultNamespacePrefix, bool isIgnoreNamespace) : base(from, selects) => (DefaultNamespacePrefix, IsIgnoreNamespace) = (defaultNamespacePrefix, isIgnoreNamespace); @@ -35,7 +36,7 @@ public override IEnumerable Execute(TextReader textReader) if (namespaceNode.Name.LocalName != "xmlns") nsMgr.AddNamespace(namespaceNode.Name.LocalName, namespaceNode.Value); - var result = from item in items.XPathSelectElements(From, nsMgr) + var result = from item in items.XPathSelectElements(From.Execute(), nsMgr) select GetObj(item, nsMgr); return result; @@ -57,7 +58,7 @@ protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceR yield return ( ( - item.XPathSelectElement(attributeSelect.Path, ns) + item.XPathSelectElement(attributeSelect.Path.Execute(), ns) ?? new XElement("null", "(null)") ).Attribute(attributeSelect.Attribute) ?? new XAttribute("null", "(null)") @@ -67,14 +68,14 @@ protected internal IEnumerable BuildXPaths(XElement item, IXmlNamespaceR { yield return ( - item.XPathEvaluate(select.Path, ns) + item.XPathEvaluate(select.Path.Execute(), ns) ?? new XElement("null", "(null)") ); } else yield return ( - item.XPathSelectElement(select.Path, ns) + item.XPathSelectElement(select.Path.Execute(), ns) ?? new XElement("null", "(null)") ).Value; } diff --git a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs index 3371d065b..6d9a28894 100644 --- a/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ResultSetResolverArgsBuilder.cs @@ -224,10 +224,10 @@ private ResultSetResolverArgs BuildXPathResolverArgs(XmlSourceXml xmlSource) var selects = new List(); var selectFactory = new PathFlattenizerFactory(); foreach (var select in xmlSource.XPath.Selects) - selects.Add(selectFactory.Instantiate(select.Value, select.Attribute, select.Evaluate)); + selects.Add(selectFactory.Instantiate(helper.InstantiateResolver(select.Value), select.Attribute, select.Evaluate)); var flattenizer = new XPathArgs { - From = xmlSource.XPath.From.Value, + From = helper.InstantiateResolver(xmlSource.XPath.From.Value), Selects = selects, DefaultNamespacePrefix = xmlSource.XPath?.DefaultNamespacePrefix, IsIgnoreNamespace = xmlSource.IgnoreNamespace @@ -261,10 +261,10 @@ private ResultSetResolverArgs BuildJsonPathResolverArgs(JsonSourceXml jsonSource var selects = new List(); var selectFactory = new PathFlattenizerFactory(); foreach (var select in jsonSource.JsonPath.Selects) - selects.Add(selectFactory.Instantiate(select.Value, string.Empty, false)); + selects.Add(selectFactory.Instantiate(helper.InstantiateResolver(select.Value), string.Empty, false)); var flattenizer = new JsonPathArgs { - From = jsonSource.JsonPath.From.Value, + From = helper.InstantiateResolver(jsonSource.JsonPath.From.Value), Selects = selects, }; diff --git a/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs b/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs index 2e48a0442..789edc0ff 100644 --- a/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs +++ b/NBi.Testing.Core/DataSerialization/Flattenizer/JsonPathEngineTest.cs @@ -1,5 +1,6 @@ using NBi.Core.DataSerialization.Flattening; using NBi.Core.DataSerialization.Flattening.Json; +using NBi.Core.Scalar.Resolver; using NUnit.Framework; using System; using System.Collections.Generic; @@ -31,12 +32,12 @@ public void Execute_Example_RowCount(string from, int rowCount) { var selects = new List() { - new ElementSelect("$") + new ElementSelect(new LiteralScalarResolver("$")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(rowCount)); } @@ -48,12 +49,12 @@ public void Execute_Example_FirstColumnIsCorrect() var from = "$.PurchaseOrders[*].Items[*]"; var selects = new List() { - new ElementSelect("PartNumber") + new ElementSelect(new LiteralScalarResolver("PartNumber")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(5)); Assert.That(result.Select(x => ((x as IEnumerable).ElementAt(0) as string).Length), Is.All.EqualTo(6)); //Format is 123-XY @@ -66,13 +67,13 @@ public void Execute_Example_AllColumnsAreCorrect() var from = "$.PurchaseOrders[*].Items[*]"; var selects = new List() { - new ElementSelect("PartNumber"), - new ElementSelect("Quantity") + new ElementSelect(new LiteralScalarResolver("PartNumber")), + new ElementSelect(new LiteralScalarResolver("Quantity")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(5)); Assert.That(result.Count, Is.EqualTo(5)); @@ -88,12 +89,12 @@ public void Execute_FromElement_ValueCorrect() var from = "$.PurchaseOrders[*].Items[*].ProductName"; var selects = new List() { - new ElementSelect("$") + new ElementSelect(new LiteralScalarResolver("$")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } @@ -105,12 +106,12 @@ public void Execute_FromAttribute_ValueCorrect() var from = "$.PurchaseOrders[*].Items[*]"; var selects = new List() { - new ElementSelect("$.PartNumber") + new ElementSelect(new LiteralScalarResolver("$.PartNumber")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } @@ -122,12 +123,12 @@ public void Execute_MissingElement_Null() var from = "$.PurchaseOrders[*]"; var selects = new List() { - new ElementSelect("$.PurchaseOrderNumber") + new ElementSelect(new LiteralScalarResolver("$.PurchaseOrderNumber")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That((result.ElementAt(3) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } @@ -139,13 +140,13 @@ public void Execute_ParentElement_ValueCorrect() var from = "$.PurchaseOrders[*].Items[*]"; var selects = new List() { - new ElementSelect("!!.PurchaseOrderNumber"), - new ElementSelect("$.PartNumber") + new ElementSelect(new LiteralScalarResolver("!!.PurchaseOrderNumber")), + new ElementSelect(new LiteralScalarResolver("$.PartNumber")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("99503")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); @@ -164,13 +165,13 @@ public void Execute_ParentElementGoingAboveRoot_ValueCorrect() var from = "$.PurchaseOrders[*].Items[*]"; var selects = new List() { - new ElementSelect("!!!!!!.PurchaseOrderNumber"), - new ElementSelect("$.PartNumber") + new ElementSelect(new LiteralScalarResolver("!!!!!!.PurchaseOrderNumber")), + new ElementSelect(new LiteralScalarResolver("$.PartNumber")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new JsonPathEngine(from, selects); + var engine = new JsonPathEngine(new LiteralScalarResolver(from), selects); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("(null)")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(1), Does.Contain("872-AA")); diff --git a/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs b/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs index 0bd7c5319..eb9f8d13a 100644 --- a/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs +++ b/NBi.Testing.Core/DataSerialization/Flattenizer/XPathEngineTest.cs @@ -1,5 +1,6 @@ using NBi.Core.DataSerialization.Flattening; using NBi.Core.DataSerialization.Flattening.Xml; +using NBi.Core.Scalar.Resolver; using NUnit.Framework; using System; using System.Collections.Generic; @@ -29,14 +30,14 @@ public void Execute_Example_ColumnCount() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new ElementSelect("//PurchaseOrder/PurchaseOrderNumber") - , new AttributeSelect(".", "PartNumber") - , new ElementSelect("//PurchaseOrder/Address[@Type=\"Shiping\"]/City") + new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/PurchaseOrderNumber")) + , new AttributeSelect(new LiteralScalarResolver("."), "PartNumber") + , new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/Address[@Type=\"Shiping\"]/City")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).Count, Is.EqualTo(3)); } @@ -49,14 +50,14 @@ public void Execute_Example_RowCount(string from, int rowCount) { var selects = new List() { - new ElementSelect("//PurchaseOrder/PurchaseOrderNumber") - , new AttributeSelect(".","PartNumber") - , new ElementSelect("//PurchaseOrder/Address[@Type=\"Shiping\"]/City") + new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/PurchaseOrderNumber")) + , new AttributeSelect(new LiteralScalarResolver("."),"PartNumber") + , new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/Address[@Type=\"Shiping\"]/City")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That(result.Count, Is.EqualTo(rowCount)); } @@ -68,12 +69,12 @@ public void Execute_FromElement_ValueCorrect() var from = "//PurchaseOrder/Items/Item/ProductName"; var selects = new List() { - new ElementSelect(".") + new ElementSelect(new LiteralScalarResolver(".")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } @@ -85,12 +86,12 @@ public void Execute_FromAttribute_ValueCorrect() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new AttributeSelect(".","PartNumber") + new AttributeSelect(new LiteralScalarResolver("."),"PartNumber") }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } @@ -102,12 +103,12 @@ public void Execute_ChildElement_ValueCorrect() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new ElementSelect("//PurchaseOrder/Items/Item/ProductName") + new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/Items/Item/ProductName")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } @@ -119,12 +120,12 @@ public void Execute_ChildAttribute_ValueCorrect() var from = "//PurchaseOrder/Items"; var selects = new List() { - new AttributeSelect("//PurchaseOrder/Items/Item","PartNumber") + new AttributeSelect(new LiteralScalarResolver("//PurchaseOrder/Items/Item"),"PartNumber") }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("872-AA")); } @@ -136,12 +137,12 @@ public void Execute_ParentElement_ValueCorrect() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new ElementSelect("//PurchaseOrder") + new ElementSelect(new LiteralScalarResolver("//PurchaseOrder")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("Ellen Adams")); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Does.Contain("Maple Street")); @@ -154,12 +155,12 @@ public void Execute_ParentAttribute_ValueCorrect() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new AttributeSelect("//PurchaseOrder","PurchaseOrderNumber") + new AttributeSelect(new LiteralScalarResolver("//PurchaseOrder"),"PurchaseOrderNumber") }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("99503")); } @@ -171,12 +172,12 @@ public void Execute_MissingElement_Null() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new ElementSelect("//PurchaseOrder/Missing") + new ElementSelect(new LiteralScalarResolver("//PurchaseOrder/Missing")) }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } @@ -188,12 +189,12 @@ public void Execute_MissingAttribute_ValueCorrect() var from = "//PurchaseOrder/Items/Item"; var selects = new List() { - new AttributeSelect("//PurchaseOrder", "Missing") + new AttributeSelect(new LiteralScalarResolver("//PurchaseOrder"), "Missing") }; using (var reader = GetResourceReader("PurchaseOrders")) { - var engine = new XPathEngine(from, selects, string.Empty, false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, string.Empty, false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("(null)")); } @@ -205,12 +206,12 @@ public void Execute_FromElementWithDefaultNamespace_ValueCorrect() var from = "//prefix:PurchaseOrder/prefix:Items/prefix:Item/prefix:ProductName"; var selects = new List() { - new ElementSelect(".") + new ElementSelect(new LiteralScalarResolver(".")) }; using (var reader = GetResourceReader("PurchaseOrdersDefaultNamespace")) { - var engine = new XPathEngine(from, selects, "prefix", false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, "prefix", false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } @@ -222,12 +223,12 @@ public void Execute_FromElementWithDefaultNamespaceAndIgnoreDefaultNamespace_Val var from = "//PurchaseOrder/Items/Item/ProductName"; var selects = new List() { - new ElementSelect(".") + new ElementSelect(new LiteralScalarResolver(".")) }; using (var reader = GetResourceReader("PurchaseOrdersDefaultNamespace")) { - var engine = new XPathEngine(from, selects, "prefix", true); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, "prefix", true); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("Lawnmower")); } @@ -239,12 +240,12 @@ public void Execute_FromElementWithManyNamespaces_ValueCorrect() var from = "//prefix:PurchaseOrder/adr:Address/prefix:Street"; var selects = new List() { - new ElementSelect(".") + new ElementSelect(new LiteralScalarResolver(".")) }; using (var reader = GetResourceReader("PurchaseOrdersManyNamespaces")) { - var engine = new XPathEngine(from, selects, "prefix", false); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, "prefix", false); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("123 Maple Street")); } @@ -256,12 +257,12 @@ public void Execute_FromElementWithManyNamespacesIgnoringDefaultNamespace_ValueC var from = "//PurchaseOrder/Address/Street"; var selects = new List() { - new ElementSelect(".") + new ElementSelect(new LiteralScalarResolver(".")) }; using (var reader = GetResourceReader("PurchaseOrdersManyNamespaces")) { - var engine = new XPathEngine(from, selects, "prefix", true); + var engine = new XPathEngine(new LiteralScalarResolver(from),selects, "prefix", true); var result = engine.Execute(reader); Assert.That((result.ElementAt(0) as IEnumerable).ElementAt(0), Is.EqualTo("123 Maple Street")); } diff --git a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits index dfbe279f7..86344981d 100644 --- a/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits +++ b/NBi.Testing/Acceptance/Resources/Positive/ResultSetConstraint.nbits @@ -40,6 +40,21 @@ + + + + + + + + + @@ -647,6 +662,38 @@ + + + + + ..\Csv\PurchaseOrders.xml + + ~//PurchaseOrder[@OrderDate="{@purchaseOrderDate:yyyy-MM-dd}"]/Items/Item + + + + + + + + + + + 99505 + 456-NM + + + 99504 + 898-AZ + + + 99504 + 898-AM + + + + + @@ -752,6 +799,33 @@ + + + + + + entries + animals + + + ~$.entries[{@one}] + + + + + + + + + + + Cats + unknown + + + + + From e7d06ff26a5b4ad5d092345742b9abff24341a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Tue, 14 Jan 2020 23:54:38 +0100 Subject: [PATCH 55/57] Fix display issue in the exception message --- NBi.Xml/Settings/SettingsXml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NBi.Xml/Settings/SettingsXml.cs b/NBi.Xml/Settings/SettingsXml.cs index 26eddb1c9..8175d334c 100644 --- a/NBi.Xml/Settings/SettingsXml.cs +++ b/NBi.Xml/Settings/SettingsXml.cs @@ -116,11 +116,11 @@ internal void GetValuesFromConfig(NameValueCollection connectionStrings) if (!string.IsNullOrEmpty(def.ConnectionString.Inline) && def.ConnectionString.Inline.StartsWith("@")) { if (connectionStrings.Count == 0) - throw new ArgumentOutOfRangeException(string.Format("No connectionString is provided through the config file. The default connection string stipulated in nbits file is trying to reference a connection string named '{0}'", def.ConnectionString)); + throw new ArgumentOutOfRangeException($"No connection-string is provided through the config file. The default connection string stipulated in the nbits file is trying to reference a connection string named '{def.ConnectionString.Inline}'"); var key = connectionStrings.AllKeys.SingleOrDefault(k => k == def.ConnectionString.Inline.Substring(1) || k == def.ConnectionString.Inline); if (string.IsNullOrEmpty(key)) - throw new ArgumentOutOfRangeException(string.Format("Some connectionStrings are provided through the config file but the default connection string is trying to reference a connection string named '{0}' which has not been found.", def.ConnectionString)); + throw new ArgumentOutOfRangeException($"Some connection-strings are provided through the config file but the default connection string is trying to reference a connection string named '{def.ConnectionString.Inline}' which has not been found."); def.ConnectionString.Inline = connectionStrings.Get(key); } From bfab9f81f8594cc78df68ab27c75742b77a7317a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 3 Feb 2020 23:30:32 +0100 Subject: [PATCH 56/57] Add new action to load optional file --- .../Case/LoadFileOptionalCaseActionTest.cs | 38 +++++++++++++++++++ .../Action/Case/LoadCaseFromFileAction.cs | 4 +- .../Case/LoadOptionalCaseFromFileAction.cs | 35 +++++++++++++++++ NBi.genbiL/NBi.genbiL.csproj | 1 + 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 NBi.Testing.GenbiL/Action/Case/LoadFileOptionalCaseActionTest.cs create mode 100644 NBi.genbiL/Action/Case/LoadOptionalCaseFromFileAction.cs diff --git a/NBi.Testing.GenbiL/Action/Case/LoadFileOptionalCaseActionTest.cs b/NBi.Testing.GenbiL/Action/Case/LoadFileOptionalCaseActionTest.cs new file mode 100644 index 000000000..432972379 --- /dev/null +++ b/NBi.Testing.GenbiL/Action/Case/LoadFileOptionalCaseActionTest.cs @@ -0,0 +1,38 @@ +using NBi.GenbiL; +using NBi.GenbiL.Action.Case; +using NBi.GenbiL.Stateful; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NBi.Testing.GenbiL.Action.Case +{ + public class LoadFileOptionalCaseActionTest + { + public class LoadOptionalCaseFromFileActionTestable : LoadOptionalCaseFromFileAction + { + public LoadOptionalCaseFromFileActionTestable(string filename, IEnumerable columnNames) + : base(filename, columnNames) { } + + protected override bool IsExistingFile() => false; + } + + [Test] + public void Execute_FileMissing_EmptyDataSetWithExpectedColumns() + { + var state = new GenerationState(); + var action = new LoadOptionalCaseFromFileActionTestable("file.csv", new[] { "foo", "bar" }); + action.Execute(state); + + var caseSet = state.CaseCollection.First().Value; + Assert.That(caseSet.Content.Rows, Has.Count.EqualTo(0)); + Assert.That(caseSet.Content.Columns, Has.Count.EqualTo(2)); + Assert.That(caseSet.Content.Columns.Cast().Select(x => x.ColumnName), Does.Contain("foo")); + Assert.That(caseSet.Content.Columns.Cast().Select(x => x.ColumnName), Does.Contain("bar")); + } + } +} diff --git a/NBi.genbiL/Action/Case/LoadCaseFromFileAction.cs b/NBi.genbiL/Action/Case/LoadCaseFromFileAction.cs index 5c675f18d..d2156048f 100644 --- a/NBi.genbiL/Action/Case/LoadCaseFromFileAction.cs +++ b/NBi.genbiL/Action/Case/LoadCaseFromFileAction.cs @@ -15,13 +15,13 @@ public LoadCaseFromFileAction(string filename) public void Execute(GenerationState state) => Execute(state.CaseCollection.CurrentScope); - public void Execute(CaseSet testCases) + public virtual void Execute(CaseSet testCases) { var csvReader = new CsvReader(); testCases.Content = csvReader.ToDataTable(Filename, true); testCases.Content.AcceptChanges(); } - public string Display => $"Loading TestCases from CSV file '{Filename}'"; + public virtual string Display => $"Loading TestCases from CSV file '{Filename}'"; } } diff --git a/NBi.genbiL/Action/Case/LoadOptionalCaseFromFileAction.cs b/NBi.genbiL/Action/Case/LoadOptionalCaseFromFileAction.cs new file mode 100644 index 000000000..8a5690711 --- /dev/null +++ b/NBi.genbiL/Action/Case/LoadOptionalCaseFromFileAction.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using NBi.Core.FlatFile; +using NBi.GenbiL.Stateful; + +namespace NBi.GenbiL.Action.Case +{ + public class LoadOptionalCaseFromFileAction : LoadCaseFromFileAction + { + public IEnumerable ColumnNames { get; set; } + + public LoadOptionalCaseFromFileAction(string filename, IEnumerable columnNames) + : base(filename) => ColumnNames = columnNames; + + public override void Execute(CaseSet testCases) + { + if (IsExistingFile()) + base.Execute(testCases); + else + { + testCases.Content = new DataTable(); + foreach (var columnName in ColumnNames) + testCases.Content.Columns.Add(new DataColumn(columnName, typeof(object))); + testCases.Content.AcceptChanges(); + } + } + + protected virtual bool IsExistingFile() => File.Exists(Filename); + + public override string Display => $"Loading test-cases from CSV file '{Filename}', if missing create empty test-case with following columns {string.Join(", ", ColumnNames)}."; + } +} diff --git a/NBi.genbiL/NBi.genbiL.csproj b/NBi.genbiL/NBi.genbiL.csproj index 86e9aeb76..7ceccf817 100644 --- a/NBi.genbiL/NBi.genbiL.csproj +++ b/NBi.genbiL/NBi.genbiL.csproj @@ -68,6 +68,7 @@ + From 7671306fc75423c7a50f0267a61281f07ff071d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Mon, 3 Feb 2020 23:30:45 +0100 Subject: [PATCH 57/57] Add parser for the load optional --- NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj | 1 + NBi.Testing.GenbiL/Parser/CaseParserTest.cs | 13 +++++++++++++ NBi.genbiL/Parser/Case.cs | 15 ++++++++++++++- NBi.genbiL/Parser/Keyword.cs | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj b/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj index ea835a0d3..c23bfcf84 100644 --- a/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj +++ b/NBi.Testing.GenbiL/NBi.Testing.GenbiL.csproj @@ -62,6 +62,7 @@ + diff --git a/NBi.Testing.GenbiL/Parser/CaseParserTest.cs b/NBi.Testing.GenbiL/Parser/CaseParserTest.cs index 517c09872..3b8f7bd99 100644 --- a/NBi.Testing.GenbiL/Parser/CaseParserTest.cs +++ b/NBi.Testing.GenbiL/Parser/CaseParserTest.cs @@ -23,6 +23,19 @@ public void SentenceParser_CaseLoadFileString_ValidCaseLoadSentence() Assert.That(((LoadCaseFromFileAction)result).Filename, Is.EqualTo("filename.csv")); } + [Test] + public void SentenceParser_CaseLoadOptionalFileString_ValidCaseLoadOptionalSentence() + { + var input = "case load optional file 'filename.csv' with columns 'foo', 'bar';"; + var result = Case.Parser.Parse(input); + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.InstanceOf()); + Assert.That(((LoadOptionalCaseFromFileAction)result).Filename, Is.EqualTo("filename.csv")); + Assert.That(((LoadOptionalCaseFromFileAction)result).ColumnNames, Does.Contain("foo")); + Assert.That(((LoadOptionalCaseFromFileAction)result).ColumnNames, Does.Contain("bar")); + } + [Test] public void SentenceParser_CaseLoadQueryFileString_ValidCaseLoadSentence() { diff --git a/NBi.genbiL/Parser/Case.cs b/NBi.genbiL/Parser/Case.cs index a56123869..6fd3dfd4e 100644 --- a/NBi.genbiL/Parser/Case.cs +++ b/NBi.genbiL/Parser/Case.cs @@ -29,6 +29,18 @@ from filename in Grammar.QuotedTextual select new LoadCaseFromFileAction(filename) ); + readonly static Parser caseLoadOptionalFileParser = + ( + from load in Keyword.Load + from optional in Keyword.Optional + from loadType in loadTypeFileParser + from filename in Grammar.QuotedTextual + from with in Keyword.With + from columns in Keyword.Columns.Or(Keyword.Column) + from columnNames in Grammar.QuotedRecordSequence + select new LoadOptionalCaseFromFileAction(filename, columnNames) + ); + readonly static Parser caseLoadQueryFileParser = ( from load in Keyword.Load @@ -50,7 +62,7 @@ from connectionString in Grammar.QuotedTextual ); readonly static Parser caseLoadParser = - caseLoadFileParser.Or(caseLoadQueryFileParser).Or(caseLoadQueryParser); + caseLoadFileParser.Or(caseLoadOptionalFileParser).Or(caseLoadQueryFileParser).Or(caseLoadQueryParser); readonly static Parser caseRemoveParser = ( @@ -105,6 +117,7 @@ from text in Grammar.ExtendedQuotedRecordSequence select new FilterCaseAction(variableName, @operator, text, negation.IsDefined) ); + readonly static Parser caseScopeParser = ( from scope in Keyword.Scope diff --git a/NBi.genbiL/Parser/Keyword.cs b/NBi.genbiL/Parser/Keyword.cs index f5d634f67..564c126e6 100644 --- a/NBi.genbiL/Parser/Keyword.cs +++ b/NBi.genbiL/Parser/Keyword.cs @@ -62,5 +62,6 @@ class Keyword public static readonly Parser Left = Parse.IgnoreCase("Left").Text().Token(); public static readonly Parser Right = Parse.IgnoreCase("Right").Text().Token(); public static readonly Parser All = Parse.IgnoreCase("All").Text().Token(); + public static readonly Parser Optional = Parse.IgnoreCase("Optional").Text().Token(); } }