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] 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 @@ public IEnumerable GetTestCases() } else if (variable.Environment != null) builder.Setup(variable.Environment); + else if (variable.Custom != null) + builder.Setup(variable.Custom); builder.Build(); var args = builder.GetArgs(); diff --git a/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs b/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs index cf1c9e8ee..6d7d683c9 100644 --- a/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs +++ b/NBi.NUnit/Builder/Helper/ScalarResolverArgsBuilder.cs @@ -11,6 +11,7 @@ using NBi.Xml.Settings; using NBi.Xml.Systems; using NBi.Xml.Variables; +using NBi.Xml.Variables.Custom; using System; using System.Collections.Generic; using System.IO; @@ -71,6 +72,15 @@ public void Build() case EnvironmentXml obj: args = new EnvironmentScalarResolverArgs(obj.Name); break; + case CustomScalarXml obj: + var helper = new ScalarHelper(ServiceLocator, Context); + args = new CustomScalarResolverArgs( + 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; 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}"