diff --git a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj index 8d11bee..1770242 100644 --- a/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj +++ b/ZeroLevel.Discovery/ZeroLevel.Discovery.csproj @@ -43,7 +43,7 @@ ..\packages\Microsoft.Owin.Hosting.4.0.1\lib\net45\Microsoft.Owin.Hosting.dll - C:\Users\a.bozhenov\source\repos\ZeroTests\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll ..\packages\Owin.1.0\lib\net40\Owin.dll diff --git a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache index e40d599..ed9d14b 100644 --- a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache +++ b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -baf2f9d75e4982e81a51362dec180283f7786a6a +affe24c0b0d3f87817c2fa3318e87e4ecf28560f diff --git a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache index d2dc83f..e6bf7b1 100644 Binary files a/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache and b/ZeroLevel.Discovery/obj/Debug/ZeroLevel.Discovery.csprojAssemblyReference.cache differ diff --git a/ZeroLevel.UnitTests/ArrayToolsTest.cs b/ZeroLevel.UnitTests/ArrayToolsTest.cs new file mode 100644 index 0000000..fd21dd6 --- /dev/null +++ b/ZeroLevel.UnitTests/ArrayToolsTest.cs @@ -0,0 +1,90 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using ZeroLevel; + +namespace ZeroArrayExtensionsTest +{ + [TestClass] + public class ArrayExtensionsTest + { + internal class EQDTO + { + public byte[] Arr; + public DateTime Date; + public string Title; + public long Num; + + public override bool Equals(object obj) + { + return this.Equals(obj as EQDTO); + } + + public bool Equals(EQDTO other) + { + if (other == null) return false; + + if (ArrayExtensions.UnsafeEquals(this.Arr, other.Arr) == false) return false; + if (DateTime.Compare(this.Date, other.Date) != 0) return false; + if (string.Compare(this.Title, other.Title, StringComparison.OrdinalIgnoreCase) != 0) return false; + return this.Num == other.Num; + } + } + + [TestMethod] + public void ByteArrayEqualTest() + { + // Arrange + var a1 = new byte[] { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 7 }; + var a2 = new byte[] { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 7 }; + var a3 = new byte[] { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9 }; + var a4 = new byte[] { 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 7 }; + byte[] a5 = null; + byte[] a6 = null; + var a7 = new byte[0]; + var a8 = new byte[0]; + + // Assert + Assert.IsTrue(ArrayExtensions.UnsafeEquals(a1, a2)); + Assert.IsTrue(ArrayExtensions.UnsafeEquals(a5, a6)); + Assert.IsTrue(ArrayExtensions.UnsafeEquals(a7, a8)); + + Assert.IsFalse(ArrayExtensions.UnsafeEquals(a1, a3)); + Assert.IsFalse(ArrayExtensions.UnsafeEquals(a1, a4)); + + Assert.IsFalse(ArrayExtensions.UnsafeEquals(a1, a5)); + Assert.IsFalse(ArrayExtensions.UnsafeEquals(a1, a7)); + + Assert.IsFalse(ArrayExtensions.UnsafeEquals(a5, a7)); + } + + [TestMethod] + public void ArrayEqualTest() + { + // Arrange + var date = DateTime.Now; + var arr1 = new EQDTO[] + { + new EQDTO { Arr = new byte[] { 1,2,3}, Date = date, Num = 10, Title = "t1" }, + new EQDTO { Arr = new byte[] { 1,2,4}, Date = date, Num = 20, Title = "t2" }, + new EQDTO { Arr = new byte[] { 1,2,5}, Date = date, Num = 30, Title = "t3" }, + new EQDTO { Arr = new byte[] { 1,2,6}, Date = date, Num = 40, Title = "t4" }, + new EQDTO { Arr = new byte[] { 1,2,7}, Date = date, Num = 50, Title = "t5" } + }; + var arr2 = new EQDTO[] + { + new EQDTO { Arr = new byte[] { 1,2,6}, Date = date, Num = 40, Title = "t4" }, + new EQDTO { Arr = new byte[] { 1,2,7}, Date = date, Num = 50, Title = "t5" } + }; + var arr3 = new EQDTO[] + { + new EQDTO { Arr = new byte[] { 1,2,6}, Date = date, Num = 40, Title = "t4" }, + new EQDTO { Arr = new byte[] { 1,2,7}, Date = date, Num = 50, Title = "t5" }, + new EQDTO { Arr = new byte[] { 1,2,7}, Date = date, Num = 50, Title = "t6" }, + }; + + //Assert + Assert.IsTrue(ArrayExtensions.Contains(arr1, arr2)); + Assert.IsFalse(ArrayExtensions.Contains(arr1, arr3)); + } + } +} diff --git a/ZeroLevel.UnitTests/InvokingTest.cs b/ZeroLevel.UnitTests/InvokingTest.cs new file mode 100644 index 0000000..4b170a6 --- /dev/null +++ b/ZeroLevel.UnitTests/InvokingTest.cs @@ -0,0 +1,165 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Reflection; +using ZeroInvokingTest.Models; +using ZeroLevel.Services.Invokation; + +namespace ZeroInvokingTest +{ + [TestClass] + public class InvokingTest + { + [TestMethod] + public void InvokeTypeAllMethod() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + invoker.Configure(); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); + // Assert + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + var date = DateTime.Now; + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + } + + [TestMethod] + public void InvokeTypeMethodByName() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + //invoker.Configure("GetString"); + invoker.Configure("GetHelp"); + invoker.Configure("GetNumber"); + invoker.Configure("GetDateTime"); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); + // Assert + try + { + var obj = invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }); + Assert.Fail("An exception should have been thrown"); + } + catch { } + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + var date = DateTime.Now; + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + } + + [TestMethod] + public void InvokeTypeMethodByFilter() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + invoker.Configure(m => m.Name.Equals("GetHelp") || m.Name.Equals("GetNumber")); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); + // Assert + try + { + var obj = invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }); + Assert.Fail("An exception should have been thrown"); + } + catch { } + try + { + var date = DateTime.Now; + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); + Assert.Fail("An exception should have been thrown"); + } + catch { } + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + } + + [TestMethod] + public void InvokeByMethodsList() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + invoker.Configure(new MethodInfo[] + { + typeof(FakeClass).GetMethod("GetHelp", BindingFlags.Public | BindingFlags.FlattenHierarchy| BindingFlags.Instance), + typeof(FakeClass).GetMethod("GetNumber", BindingFlags.NonPublic| BindingFlags.Instance), + typeof(FakeClass).GetMethod("GetDateTime", BindingFlags.NonPublic| BindingFlags.Instance), + typeof(FakeClass).GetMethod("GetString") + }); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); + // Assert + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + var date = DateTime.Now; + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + } + + [TestMethod] + public void InvokeByMethods() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + invoker.Configure(typeof(FakeClass).GetMethod("GetHelp", BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance)); + invoker.Configure(typeof(FakeClass).GetMethod("GetNumber", BindingFlags.NonPublic | BindingFlags.Instance)); + invoker.Configure(typeof(FakeClass).GetMethod("GetDateTime", BindingFlags.NonPublic | BindingFlags.Instance)); + invoker.Configure(typeof(FakeClass).GetMethod("GetString")); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + var identityGetHelp = invoker.GetInvokerIdentity("GetHelp", null); + // Assert + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetString, new object[] { "hello" }), "hello"); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetNumber, new object[] { 100 }), 100); + var date = DateTime.Now; + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetDateTime, new object[] { date }), date); + Assert.AreEqual(invoker.Invoke(new FakeClass(), identityGetHelp), "help"); + } + + [TestMethod] + public void InvokeStaticByMethods() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + invoker.Configure(typeof(StaticFakeClass).GetMethod("GetNumber", BindingFlags.NonPublic | BindingFlags.Static)); + invoker.Configure(typeof(StaticFakeClass).GetMethod("GetDateTime", BindingFlags.NonPublic | BindingFlags.Static)); + invoker.Configure(typeof(StaticFakeClass).GetMethod("GetString")); + var identityGetString = invoker.GetInvokerIdentity("GetString", new Type[] { typeof(string) }); + var identityGetNumber = invoker.GetInvokerIdentity("GetNumber", new Type[] { typeof(int) }); + var identityGetDateTime = invoker.GetInvokerIdentity("GetDateTime", new Type[] { typeof(DateTime) }); + // Assert + Assert.AreEqual(invoker.InvokeStatic(identityGetString, new object[] { "hello" }), "hello"); + Assert.AreEqual(invoker.InvokeStatic(identityGetNumber, new object[] { 100 }), 100); + var date = DateTime.Now; + Assert.AreEqual(invoker.InvokeStatic(identityGetDateTime, new object[] { date }), date); + } + + [TestMethod] + public void InvokeByDelegate() + { + // Arrange + var invoker = InvokeWrapper.Create(); + // Act + var func = new Func(str => str.Length > 0); + var name = invoker.Configure(func); + // Assert + Assert.IsTrue((bool)invoker.Invoke(func.Target, name, new object[] { "hello" })); + } + } +} diff --git a/ZeroLevel.UnitTests/MappingTest.cs b/ZeroLevel.UnitTests/MappingTest.cs new file mode 100644 index 0000000..02fe775 --- /dev/null +++ b/ZeroLevel.UnitTests/MappingTest.cs @@ -0,0 +1,207 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ZeroLevel.Services.ObjectMapping; +using ZeroMappingTest.Models; +using System.Collections.Generic; + +namespace ZeroMappingTest +{ + [TestClass] + public class MappingTest + { + [TestMethod] + public void TestAbstractClassGetInfo() + { + // Arrange + var mapper = TypeMapper.Create(); + // Act + var list = new List(); + mapper.TraversalMembers(f => list.Add(f.Name)); + // Assert + Assert.IsTrue(mapper.Exists("Id")); + Assert.IsTrue(mapper.Exists("Title")); + Assert.IsTrue(mapper.Exists("Description")); + + Assert.IsTrue(list.Contains("Id")); + Assert.IsTrue(list.Contains("Title")); + Assert.IsTrue(list.Contains("Description")); + + Assert.IsFalse(mapper.Exists("Version")); + Assert.IsFalse(mapper.Exists("Created")); + + Assert.IsFalse(list.Contains("Version")); + Assert.IsFalse(list.Contains("Created")); + + Assert.AreEqual(mapper.EntityType, typeof(BaseClass)); + } + + [TestMethod] + public void TestInheritedClassGetInfo() + { + // Arrange + var mapper = TypeMapper.Create(); + // Act + var list = new List(); + mapper.TraversalMembers(f => list.Add(f.Name)); + // Assert + Assert.IsTrue(mapper.Exists("Id")); + Assert.IsTrue(mapper.Exists("Title")); + Assert.IsTrue(mapper.Exists("Description")); + Assert.IsTrue(mapper.Exists("Number")); + Assert.IsTrue(mapper.Exists("Balance")); + Assert.IsTrue(mapper.Exists("ReadOnlyProperty")); + Assert.IsTrue(mapper.Exists("WriteOnlyProperty")); + + Assert.IsTrue(list.Contains("Id")); + Assert.IsTrue(list.Contains("Title")); + Assert.IsTrue(list.Contains("Description")); + Assert.IsTrue(list.Contains("Number")); + Assert.IsTrue(list.Contains("Balance")); + Assert.IsTrue(list.Contains("ReadOnlyProperty")); + Assert.IsTrue(list.Contains("WriteOnlyProperty")); + + Assert.IsFalse(mapper.Exists("HiddenField")); + Assert.IsFalse(mapper.Exists("Version")); + Assert.IsFalse(mapper.Exists("Created")); + + Assert.IsFalse(list.Contains("HiddenField")); + Assert.IsFalse(list.Contains("Version")); + Assert.IsFalse(list.Contains("Created")); + + Assert.AreEqual(mapper.EntityType, typeof(ChildClass)); + } + + [TestMethod] + public void TestAbstractClassMapping() + { + // Arrange + var instance = new ChildClass + { + Id = Guid.Empty, + Title = "title", + Description = "description", + WriteOnlyProperty = 100, + Balance = 100, + Number = 100 + }; + var mapper = TypeMapper.Create(); + // Act + var id = Guid.NewGuid(); + var title = "New title"; + var description = "New description"; + mapper.Set(instance, "Id", id); + mapper.Set(instance, "Title", title); + mapper.Set(instance, "Description", description); + // Assert + Assert.AreEqual(mapper.Get(instance, "Id"), id); + Assert.AreEqual(mapper.Get(instance, "Title"), title); + Assert.AreEqual(mapper.Get(instance, "Description"), description); + + Assert.AreEqual(mapper.Get(instance, "Id"), id); + Assert.AreEqual(mapper.Get(instance, "Title"), title); + Assert.AreEqual(mapper.Get(instance, "Description"), description); + try + { + mapper.Get(instance, "Number"); + Assert.Fail("Must be inaccessability"); + } + catch + { + } + } + + [TestMethod] + public void TestInheritedClassMapping() + { + // Arrange + var instance = new ChildClass + { + Id = Guid.Empty, + Title = "title", + Description = "description", + WriteOnlyProperty = 100, + Balance = 100, + Number = 100 + }; + var mapper = TypeMapper.Create(); + // Act + var id = Guid.NewGuid(); + var title = "New title"; + var description = "New description"; + var number = 5465; + var balance = 5555; + + + mapper.Set(instance, "Id", id); + mapper.Set(instance, "Title", title); + mapper.Set(instance, "Description", description); + mapper.Set(instance, "Number", number); + mapper.Set(instance, "Balance", balance); + // Assert + Assert.AreEqual(mapper.Get(instance, "Id"), id); + Assert.AreEqual(mapper.Get(instance, "Title"), title); + Assert.AreEqual(mapper.Get(instance, "Description"), description); + Assert.AreEqual(mapper.Get(instance, "Number"), number); + Assert.AreEqual(mapper.Get(instance, "Balance"), balance); + + Assert.AreEqual(mapper.Get(instance, "Id"), id); + Assert.AreEqual(mapper.Get(instance, "Title"), title); + Assert.AreEqual(mapper.Get(instance, "Description"), description); + Assert.AreEqual(mapper.Get(instance, "Number"), number); + Assert.AreEqual(mapper.Get(instance, "Balance"), balance); + + try + { + var test = 1000; + mapper.Set(instance, "ReadOnlyProperty", test); + Assert.Fail("There should be no possibility to set a value."); + } + catch + { + + } + + try + { + mapper.Get(instance, "WriteOnlyProperty"); + Assert.Fail("There should be no possibility to get a value."); + } + catch + { + + } + + try + { + mapper.GetOrDefault(instance, "WriteOnlyProperty", null); + } + catch + { + Assert.Fail("It should be possible to get the default value."); + } + + try + { + mapper.Get(instance, "Number"); + } + catch(Exception ex) + { + Assert.Fail(ex.Message); + } + } + + [TestMethod] + public void TestMapperscaching() + { + // Arrange + var mapper1 = TypeMapper.Create(); + var mapper2 = TypeMapper.Create(); + var mapper3 = TypeMapper.Create(false); + // Act + // Assert + Assert.AreSame(mapper1, mapper2); + Assert.AreNotSame(mapper1, mapper3); + Assert.AreNotSame(mapper3, mapper2); + } + } +} diff --git a/ZeroLevel.UnitTests/Models/BaseClass.cs b/ZeroLevel.UnitTests/Models/BaseClass.cs new file mode 100644 index 0000000..339cc8a --- /dev/null +++ b/ZeroLevel.UnitTests/Models/BaseClass.cs @@ -0,0 +1,14 @@ +using System; + +namespace ZeroMappingTest.Models +{ + public abstract class BaseClass + { + public Guid Id; + public string Title { get; set; } + public string Description { get; set; } + + protected long Version { get; set; } + private DateTime Created { get; set; } + } +} diff --git a/ZeroLevel.UnitTests/Models/BaseFakeClass.cs b/ZeroLevel.UnitTests/Models/BaseFakeClass.cs new file mode 100644 index 0000000..2eb89ec --- /dev/null +++ b/ZeroLevel.UnitTests/Models/BaseFakeClass.cs @@ -0,0 +1,7 @@ +namespace ZeroInvokingTest.Models +{ + public abstract class BaseFakeClass + { + public string GetHelp() => "help"; + } +} diff --git a/ZeroLevel.UnitTests/Models/ChildClass.cs b/ZeroLevel.UnitTests/Models/ChildClass.cs new file mode 100644 index 0000000..6c76e16 --- /dev/null +++ b/ZeroLevel.UnitTests/Models/ChildClass.cs @@ -0,0 +1,11 @@ +namespace ZeroMappingTest.Models +{ + public class ChildClass: + BaseClass + { + public int Number; + public int Balance { get; set; } + public int ReadOnlyProperty { get { return Number; } } + public int WriteOnlyProperty { set { Number = value; } } + } +} diff --git a/ZeroLevel.UnitTests/Models/FakeClass.cs b/ZeroLevel.UnitTests/Models/FakeClass.cs new file mode 100644 index 0000000..5aa547c --- /dev/null +++ b/ZeroLevel.UnitTests/Models/FakeClass.cs @@ -0,0 +1,11 @@ +using System; + +namespace ZeroInvokingTest.Models +{ + public class FakeClass : BaseFakeClass + { + public string GetString(string line) => line; + internal int GetNumber(int number) => number; + private DateTime GetDateTime(DateTime date) => date; + } +} diff --git a/ZeroLevel.UnitTests/Models/StaticFakeClass.cs b/ZeroLevel.UnitTests/Models/StaticFakeClass.cs new file mode 100644 index 0000000..2386e5b --- /dev/null +++ b/ZeroLevel.UnitTests/Models/StaticFakeClass.cs @@ -0,0 +1,11 @@ +using System; + +namespace ZeroInvokingTest.Models +{ + public static class StaticFakeClass + { + public static string GetString(string line) => line; + internal static int GetNumber(int number) => number; + private static DateTime GetDateTime(DateTime date) => date; + } +} diff --git a/ZeroLevel.UnitTests/Properties/AssemblyInfo.cs b/ZeroLevel.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fb56531 --- /dev/null +++ b/ZeroLevel.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("ZeroLevel.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ZeroLevel.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("c500b489-c432-499d-b0e4-b41998b12c49")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ZeroLevel.UnitTests/SerializationTests.cs b/ZeroLevel.UnitTests/SerializationTests.cs new file mode 100644 index 0000000..ea6ff88 --- /dev/null +++ b/ZeroLevel.UnitTests/SerializationTests.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ZeroLevel.Network; +using ZeroLevel.Services.Serialization; + +namespace ZeroLevel.UnitTests +{ + [TestClass] + public class SerializationTests + { + private static bool TestOrderingEquals(IEnumerable A, IEnumerable B, Func comparer) + { + if (A == null && B == null) return true; + if (A == null || B == null) return false; + if (A.Count() != B.Count()) return false; + var enumA = A.GetEnumerator(); + var enumB = B.GetEnumerator(); + while (enumA.MoveNext() && enumB.MoveNext()) + { + if (enumA.Current == null && enumB.Current == null) continue; + if (comparer(enumA.Current, enumB.Current) == false) return false; + } + return true; + } + + private void MakePrimitiveTest(T value, Func comparator = null) + { + // Act + var data = MessageSerializer.SerializeCompatible(value); + var clone = MessageSerializer.DeserializeCompatible(data); + + // Assert + if (comparator == null) + { + Assert.AreEqual(value, clone); + } + else + { + Assert.IsTrue(comparator(value, clone)); + } + } + + private void MakeCollectionTest(IEnumerable value, Func comparator = null) + { + // Act + var data = MessageSerializer.SerializeCompatible>(value); + var clone = MessageSerializer.DeserializeCompatible>(data); + + // Assert + if (value == null && clone != null && !clone.Any()) return; // OK + if (comparator == null) + { + Assert.IsTrue(CollectionComparsionExtensions.OrderingEquals(value, clone)); + } + else + { + Assert.IsTrue(TestOrderingEquals(value, clone, comparator)); + } + } + + [TestMethod] + public void SerializeDateTime() + { + MakePrimitiveTest(DateTime.Now); + MakePrimitiveTest(DateTime.UtcNow); + MakePrimitiveTest(DateTime.Today); + MakePrimitiveTest(DateTime.Now.AddYears(2000)); + MakePrimitiveTest(DateTime.MinValue); + MakePrimitiveTest(DateTime.MaxValue); + } + + [TestMethod] + public void SerializeIPAddress() + { + var comparator = new Func((left, right) => NetUtils.Compare(left, right) == 0); + MakePrimitiveTest(IPAddress.Any, comparator); + MakePrimitiveTest(IPAddress.Broadcast, comparator); + MakePrimitiveTest(IPAddress.IPv6Any, comparator); + MakePrimitiveTest(IPAddress.IPv6Loopback, comparator); + MakePrimitiveTest(IPAddress.IPv6None, comparator); + MakePrimitiveTest(IPAddress.Loopback, comparator); + MakePrimitiveTest(IPAddress.None, comparator); + MakePrimitiveTest(IPAddress.Parse("93.111.16.58"), comparator); + } + + [TestMethod] + public void SerializeIPEndPoint() + { + var comparator = new Func((left, right) => NetUtils.Compare(left, right) == 0); + MakePrimitiveTest(new IPEndPoint(IPAddress.Any, 1), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.Broadcast, 600), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.IPv6Any, IPEndPoint.MaxPort), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.IPv6Loopback, 8080), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.IPv6None, 80), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.Loopback, 9000), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.None, 0), comparator); + MakePrimitiveTest(new IPEndPoint(IPAddress.Parse("93.111.16.58"), IPEndPoint.MinPort), comparator); + } + + [TestMethod] + public void SerializeGuid() + { + MakePrimitiveTest(Guid.Empty); + MakePrimitiveTest(Guid.NewGuid()); + } + + [TestMethod] + public void SerializeTimeSpan() + { + MakePrimitiveTest(TimeSpan.MaxValue); + MakePrimitiveTest(TimeSpan.MinValue); + MakePrimitiveTest(TimeSpan.Zero); + MakePrimitiveTest(TimeSpan.FromDays(1024)); + MakePrimitiveTest(TimeSpan.FromMilliseconds(1)); + MakePrimitiveTest(TimeSpan.FromTicks(1)); + MakePrimitiveTest(TimeSpan.FromTicks(0)); + } + + [TestMethod] + public void SerializeString() + { + var comparator = new Func((left, right) => + (left == null && right == null) || + (left == null && right != null && right.Length == 0) || + (left != null && left.Length == 0 && right == null) || + string.Compare(left, right, StringComparison.InvariantCulture) == 0); + MakePrimitiveTest("", comparator); + MakePrimitiveTest(String.Empty, comparator); + MakePrimitiveTest(null, comparator); + MakePrimitiveTest("HELLO!", comparator); + MakePrimitiveTest("𐌼𐌰𐌲 𐌲𐌻𐌴𐍃 𐌹̈𐍄𐌰𐌽, 𐌽𐌹 𐌼𐌹𐍃 𐍅𐌿 𐌽𐌳𐌰𐌽 𐌱𐍂𐌹𐌲𐌲𐌹𐌸", comparator); + } + + [TestMethod] + public void SerializeInt32() + { + MakePrimitiveTest(-0); + MakePrimitiveTest(0); + MakePrimitiveTest(-10); + MakePrimitiveTest(10); + MakePrimitiveTest(Int32.MinValue); + MakePrimitiveTest(Int32.MaxValue); + } + + [TestMethod] + public void SerializeInt64() + { + MakePrimitiveTest(-0); + MakePrimitiveTest(0); + MakePrimitiveTest(-10); + MakePrimitiveTest(10); + MakePrimitiveTest(Int64.MinValue); + MakePrimitiveTest(Int64.MaxValue); + MakePrimitiveTest(Int64.MinValue / 2); + MakePrimitiveTest(Int64.MaxValue / 2); + } + + [TestMethod] + public void SerializeDecimal() + { + MakePrimitiveTest(-0); + MakePrimitiveTest(0); + MakePrimitiveTest(-10); + MakePrimitiveTest(10); + MakePrimitiveTest(Decimal.MinValue); + MakePrimitiveTest(Decimal.MaxValue); + MakePrimitiveTest(Decimal.MinValue / 2); + MakePrimitiveTest(Decimal.MaxValue / 2); + } + + [TestMethod] + public void SerializeFloat() + { + MakePrimitiveTest(-0); + MakePrimitiveTest(0); + MakePrimitiveTest(-10); + MakePrimitiveTest(10); + MakePrimitiveTest(float.MinValue); + MakePrimitiveTest(float.MaxValue); + MakePrimitiveTest(float.MinValue / 2); + MakePrimitiveTest(float.MaxValue / 2); + } + + [TestMethod] + public void SerializeDouble() + { + MakePrimitiveTest(-0); + MakePrimitiveTest(0); + MakePrimitiveTest(-10); + MakePrimitiveTest(10); + MakePrimitiveTest(Double.MinValue); + MakePrimitiveTest(Double.MaxValue); + MakePrimitiveTest(Double.MinValue / 2); + MakePrimitiveTest(Double.MaxValue / 2); + } + + [TestMethod] + public void SerializeBoolean() + { + MakePrimitiveTest(true); + MakePrimitiveTest(false); + } + + [TestMethod] + public void SerializeByte() + { + MakePrimitiveTest(0); + MakePrimitiveTest(-0); + MakePrimitiveTest(1); + MakePrimitiveTest(10); + MakePrimitiveTest(128); + MakePrimitiveTest(255); + } + + [TestMethod] + public void SerializeBytes() + { + var comparator = new Func((left, right) => + (left == null && (right == null || right.Length == 0)) || ArrayExtensions.UnsafeEquals(left, right)); + MakePrimitiveTest(null, comparator); + MakePrimitiveTest(new byte[] { }, comparator); + MakePrimitiveTest(new byte[] { 1 }, comparator); + MakePrimitiveTest(new byte[] { 0, 1, 10, 100, 128, 255 }, comparator); + } + + /* + COLLECTIONS + */ + + [TestMethod] + public void SerializeCollectionDateTime() + { + MakeCollectionTest(null); + MakeCollectionTest(new DateTime[] { }); + MakeCollectionTest(new DateTime[] { DateTime.Now, DateTime.UtcNow, DateTime.Today, DateTime.Now.AddYears(2000), DateTime.MinValue, DateTime.MaxValue }); + } + + [TestMethod] + public void SerializeCollectionIPAddress() + { + var comparator = new Func((left, right) => NetUtils.Compare(left, right) == 0); + MakeCollectionTest(null); + MakeCollectionTest(new IPAddress[] { IPAddress.Any, IPAddress.Broadcast, IPAddress.IPv6Any, IPAddress.IPv6Loopback, IPAddress.IPv6None, IPAddress.Loopback, IPAddress.None, IPAddress.Parse("93.111.16.58") }, comparator); + } + + [TestMethod] + public void SerializeCollectionIPEndPoint() + { + var comparator = new Func((left, right) => NetUtils.Compare(left, right) == 0); + MakeCollectionTest(null); + MakeCollectionTest(new IPEndPoint[] { }); + MakeCollectionTest(new IPEndPoint[] { new IPEndPoint(IPAddress.Any, 1), new IPEndPoint(IPAddress.Broadcast, 600), new IPEndPoint(IPAddress.IPv6Any, IPEndPoint.MaxPort), new IPEndPoint(IPAddress.IPv6Loopback, 8080), new IPEndPoint(IPAddress.IPv6None, 80), new IPEndPoint(IPAddress.Loopback, 9000), new IPEndPoint(IPAddress.None, 0), new IPEndPoint(IPAddress.Parse("93.111.16.58"), IPEndPoint.MinPort) }, comparator); + } + + [TestMethod] + public void SerializeCollectionGuid() + { + MakeCollectionTest(null); + MakeCollectionTest(new Guid[] { }); + MakeCollectionTest(new Guid[] { Guid.Empty, Guid.NewGuid() }); + } + + [TestMethod] + public void SerializeCollectionTimeSpan() + { + MakeCollectionTest(new TimeSpan[] { TimeSpan.MaxValue, TimeSpan.MinValue, TimeSpan.Zero, TimeSpan.FromDays(1024), TimeSpan.FromMilliseconds(1), TimeSpan.FromTicks(1), TimeSpan.FromTicks(0) }); + } + + [TestMethod] + public void SerializeCollectionString() + { + var comparator = new Func((left, right) => + (left == null && right == null) || + (left == null && right != null && right.Length == 0) || + (left != null && left.Length == 0 && right == null) || + string.Compare(left, right, StringComparison.InvariantCulture) == 0); + MakeCollectionTest(new string[] { "", String.Empty, null, "HELLO!", "𐌼𐌰𐌲 𐌲𐌻𐌴𐍃 𐌹̈𐍄𐌰𐌽, 𐌽𐌹 𐌼𐌹𐍃 𐍅𐌿 𐌽𐌳𐌰𐌽 𐌱𐍂𐌹𐌲𐌲𐌹𐌸" }, comparator); + } + + + [TestMethod] + public void SerializeCollectionInt32() + { + MakeCollectionTest(new int[] { -0, 0, -10, 10, Int32.MinValue, Int32.MaxValue }); + } + + [TestMethod] + public void SerializeCollectionInt64() + { + MakeCollectionTest(new long[] { -0, 0, -10, 10, Int64.MinValue, Int64.MaxValue, Int64.MinValue / 2, Int64.MaxValue / 2 }); + } + + [TestMethod] + public void SerializeCollectionDecimal() + { + MakeCollectionTest(new Decimal[] { -0, 0, -10, 10, Decimal.MinValue, Decimal.MaxValue, Decimal.MinValue / 2, Decimal.MaxValue / 2 }); + } + + [TestMethod] + public void SerializeCollectionFloat() + { + MakeCollectionTest(new float[] { -0, 0, -10, 10, float.MinValue, float.MaxValue, float.MinValue / 2, float.MaxValue / 2 }); + } + + [TestMethod] + public void SerializeCollectionDouble() + { + MakeCollectionTest(new Double[] { -0, 0, -10, 10, Double.MinValue, Double.MaxValue, Double.MinValue / 2, Double.MaxValue / 2 }); + } + + [TestMethod] + public void SerializeCollectionBoolean() + { + MakeCollectionTest(new Boolean[] { true, false, true }); + } + + [TestMethod] + public void SerializeCollectionByte() + { + MakeCollectionTest(new byte[] { 0, 3, -0, 1, 10, 128, 255 }); + } + + [TestMethod] + public void SerializeCollectionBytes() + { + var comparator = new Func((left, right) => + (left == null && (right == null || right.Length == 0)) || ArrayExtensions.UnsafeEquals(left, right)); + + MakeCollectionTest(new Byte[][] { null, new byte[] { }, new byte[] { 1 }, new byte[] { 0, 1, 10, 100, 128, 255 } }, comparator); + } + } +} diff --git a/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj b/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj new file mode 100644 index 0000000..12a3835 --- /dev/null +++ b/ZeroLevel.UnitTests/ZeroLevel.UnitTests.csproj @@ -0,0 +1,82 @@ + + + + + + Debug + AnyCPU + {C500B489-C432-499D-B0E4-B41998B12C49} + Library + Properties + ZeroLevel.UnitTests + ZeroLevel.UnitTests + v4.7.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + + + + + + + + + + + + + + + + + + + + {37020d8d-34e8-4ec3-a447-8396d5080457} + ZeroLevel + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/ZeroLevel.UnitTests/packages.config b/ZeroLevel.UnitTests/packages.config new file mode 100644 index 0000000..2f7c5a1 --- /dev/null +++ b/ZeroLevel.UnitTests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/ZeroLevel.sln b/ZeroLevel.sln index 279e1a3..e434381 100644 --- a/ZeroLevel.sln +++ b/ZeroLevel.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel", "ZeroLevel\Zero EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.Discovery", "ZeroLevel.Discovery\ZeroLevel.Discovery.csproj", "{4F55B23F-938C-4DA2-B6DC-B6BC66D36073}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.UnitTests", "ZeroLevel.UnitTests\ZeroLevel.UnitTests.csproj", "{C500B489-C432-499D-B0E4-B41998B12C49}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,18 @@ Global {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Release|x64.Build.0 = Release|Any CPU {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Release|x86.ActiveCfg = Release|Any CPU {4F55B23F-938C-4DA2-B6DC-B6BC66D36073}.Release|x86.Build.0 = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|x64.ActiveCfg = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|x64.Build.0 = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|x86.ActiveCfg = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Debug|x86.Build.0 = Debug|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|Any CPU.Build.0 = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|x64.ActiveCfg = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|x64.Build.0 = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|x86.ActiveCfg = Release|Any CPU + {C500B489-C432-499D-B0E4-B41998B12C49}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ZeroLevel/Services/Extensions/BitConverterExtensions.cs b/ZeroLevel/Services/Extensions/BitConverterExtensions.cs index 43186ed..d1e0cd3 100644 --- a/ZeroLevel/Services/Extensions/BitConverterExtensions.cs +++ b/ZeroLevel/Services/Extensions/BitConverterExtensions.cs @@ -16,14 +16,11 @@ namespace ZeroLevel.Services.Extensions return bytes.ToArray(); } - public static decimal ToDecimal(this byte[] bytes) + public static decimal ToDecimal(this int[] parts) { - var arr = new int[4]; - for (int i = 0; i < 15; i += 4) - { - arr[i % 4] = BitConverter.ToInt32(bytes, i); - } - return new Decimal(arr); + bool sign = (parts[3] & 0x80000000) != 0; + byte scale = (byte)((parts[3] >> 16) & 0x7F); + return new Decimal(parts[0], parts[1], parts[2], sign, scale); } } } \ No newline at end of file diff --git a/ZeroLevel/Services/Network/NetUtils.cs b/ZeroLevel/Services/Network/NetUtils.cs index 32ab76a..a825a00 100644 --- a/ZeroLevel/Services/Network/NetUtils.cs +++ b/ZeroLevel/Services/Network/NetUtils.cs @@ -16,6 +16,13 @@ namespace ZeroLevel.Network return result == 0 ? x.Port.CompareTo(y.Port) : result; } + public static int Compare(this IPAddress x, IPAddress y) + { + var xx = x.ToString(); + var yy = y.ToString(); + return string.CompareOrdinal(xx, yy); + } + public static IPEndPoint CreateIPEndPoint(string endPoint) { string[] ep = endPoint.Split(':'); diff --git a/ZeroLevel/Services/Serialization/MemoryStreamReader.cs b/ZeroLevel/Services/Serialization/MemoryStreamReader.cs index 69c07e4..54b3f9e 100644 --- a/ZeroLevel/Services/Serialization/MemoryStreamReader.cs +++ b/ZeroLevel/Services/Serialization/MemoryStreamReader.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using ZeroLevel.Services.Extensions; namespace ZeroLevel.Services.Serialization { @@ -63,8 +64,11 @@ namespace ZeroLevel.Services.Serialization public decimal ReadDecimal() { - var buffer = ReadBuffer(4); - return BitConverter.ToInt32(buffer, 0); + var p1 = ReadInt32(); + var p2 = ReadInt32(); + var p3 = ReadInt32(); + var p4 = ReadInt32(); + return BitConverterExt.ToDecimal(new int[] { p1, p2, p3, p4 }); } /// @@ -143,13 +147,13 @@ namespace ZeroLevel.Services.Serialization public IPAddress ReadIP() { - var addr = ReadLong(); + var addr = ReadBytes(); return new IPAddress(addr); } public IPEndPoint ReadIPEndpoint() { - var addr = ReadLong(); + var addr = ReadIP(); var port = ReadInt32(); return new IPEndPoint(addr, port); } diff --git a/ZeroLevel/Services/Serialization/MemoryStreamWriter.cs b/ZeroLevel/Services/Serialization/MemoryStreamWriter.cs index 2379cd3..fd13764 100644 --- a/ZeroLevel/Services/Serialization/MemoryStreamWriter.cs +++ b/ZeroLevel/Services/Serialization/MemoryStreamWriter.cs @@ -144,12 +144,12 @@ namespace ZeroLevel.Services.Serialization public void WriteIP(IPAddress ip) { - WriteLong(ip.Address); + WriteBytes(ip.GetAddressBytes()); } public void WriteIPEndpoint(IPEndPoint endpoint) { - WriteLong(endpoint.Address.Address); + WriteIP(endpoint.Address); WriteInt32(endpoint.Port); } diff --git a/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache b/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache index 1a69533..431e5cf 100644 --- a/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache +++ b/ZeroLevel/obj/Debug/ZeroLevel.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -23b05e1da25edde99ed56a899f894605a2243d39 +4d221d21073e6ec70fc75d0c6e7d2458aa0f2b9a