diff --git a/build-system/nightly-builds.yaml b/build-system/nightly-builds.yaml index c8e91b27..273c5533 100644 --- a/build-system/nightly-builds.yaml +++ b/build-system/nightly-builds.yaml @@ -2,7 +2,7 @@ # See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference pool: - vmImage: vs2017-win2016 + vmImage: windows-2019 demands: Cmd trigger: none diff --git a/build-system/pr-validation.yaml b/build-system/pr-validation.yaml index 99a80dfb..6a62781c 100644 --- a/build-system/pr-validation.yaml +++ b/build-system/pr-validation.yaml @@ -18,7 +18,7 @@ jobs: parameters: name: 'windows_pr' displayName: 'Windows PR Validation' - vmImage: 'vs2017-win2016' + vmImage: 'windows-2019' scriptFileName: build.cmd scriptArgs: all - template: azure-pipeline.template.yaml diff --git a/build-system/windows-pr-validation.yaml b/build-system/windows-pr-validation.yaml index 47f6ea3b..0b50b03e 100644 --- a/build-system/windows-pr-validation.yaml +++ b/build-system/windows-pr-validation.yaml @@ -17,6 +17,6 @@ jobs: - template: azure-pipeline.template.yaml parameters: name: Windows - vmImage: 'vs2017-win2016' + vmImage: 'windows-2019' scriptFileName: build.cmd scriptArgs: all \ No newline at end of file diff --git a/build-system/windows-release.yaml b/build-system/windows-release.yaml index 6e3b17e4..43fe3dfb 100644 --- a/build-system/windows-release.yaml +++ b/build-system/windows-release.yaml @@ -2,7 +2,7 @@ # See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference pool: - vmImage: vs2017-win2016 + vmImage: windows-2019 demands: Cmd trigger: diff --git a/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj b/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj index ae47fb53..dac98890 100644 --- a/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj +++ b/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj @@ -8,4 +8,8 @@ + + + + diff --git a/src/Hyperion.Tests/CrossFrameworkSerializationTests.cs b/src/Hyperion.Tests/CrossFrameworkSerializationTests.cs new file mode 100644 index 00000000..08d5690f --- /dev/null +++ b/src/Hyperion.Tests/CrossFrameworkSerializationTests.cs @@ -0,0 +1,37 @@ +using System.IO; +using Hyperion.Tests.Generator; +using Xunit; + +namespace Hyperion.Tests +{ + public class CrossFrameworkSerializationTests + { + private readonly Serializer _serializer; + private readonly CrossFrameworkClass _originalObject; + + public CrossFrameworkSerializationTests() + { + _serializer = new Serializer(); + _originalObject = CrossFrameworkInitializer.Init(); + } + + [Fact] + public void CanSerializeCrossFramework() + { + const string defaultOutputPath = CrossFrameworkInitializer.DefaultOutputPath; + var testFiles = Directory.GetFiles(defaultOutputPath, "*.tf"); + + Assert.NotEmpty(testFiles); + + foreach (string testFile in testFiles) + { + using (var fileStream = new FileStream(testFile, FileMode.Open)) + { + var crossFrameworkClass = _serializer.Deserialize(fileStream); + + Assert.Equal(_originalObject, crossFrameworkClass); + } + } + } + } +} diff --git a/src/Hyperion.Tests/Generator/CrossFrameworkClass.cs b/src/Hyperion.Tests/Generator/CrossFrameworkClass.cs new file mode 100644 index 00000000..081021c0 --- /dev/null +++ b/src/Hyperion.Tests/Generator/CrossFrameworkClass.cs @@ -0,0 +1,125 @@ +using System; + +namespace Hyperion.Tests.Generator +{ + public class CrossFrameworkClass + { + public sbyte Sbyte { get; set; } + + public short Short { get; set; } + + public int Int { get; set; } + + public long Long { get; set; } + + public byte Byte { get; set; } + + public ushort UShort { get; set; } + + public uint UInt { get; set; } + + public ulong ULong { get; set; } + + public char Char { get; set; } + + public float Float { get; set; } + + public double Double { get; set; } + + public decimal Decimal { get; set; } + + public bool Boolean { get; set; } + + public string String { get; set; } + + public DateTime DateTime { get; set; } + + public Exception Exception { get; set; } + + public CrossFrameworkEnum Enum { get; set; } + + public CrossFrameworkStruct Struct { get; set; } + + public override bool Equals(object obj) + { + if (!(obj is CrossFrameworkClass)) + { + return false; + } + + var objectToCompare = (CrossFrameworkClass) obj; + + + //return Sbyte == objectToCompare.Sbyte + // && Short == objectToCompare.Short + // && Int == objectToCompare.Int + // && Long == objectToCompare.Long + // && Byte == objectToCompare.Byte + // && UShort == objectToCompare.UShort + // && UInt == objectToCompare.UInt + // && ULong == objectToCompare.ULong + // && Char == objectToCompare.Char + // && Math.Abs(Float - objectToCompare.Float) < float.Epsilon + // && Math.Abs(Double - objectToCompare.Double) < double.Epsilon + // && Decimal == objectToCompare.Decimal + // && Boolean == objectToCompare.Boolean + // && String == objectToCompare.String + // && DateTime == objectToCompare.DateTime + // && Exception == objectToCompare.Exception + // && Enum == objectToCompare.Enum + // && Struct.Equals(objectToCompare.Struct); + + return Equals(objectToCompare); + + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = Sbyte.GetHashCode(); + hashCode = (hashCode * 397) ^ Short.GetHashCode(); + hashCode = (hashCode * 397) ^ Int; + hashCode = (hashCode * 397) ^ Long.GetHashCode(); + hashCode = (hashCode * 397) ^ Byte.GetHashCode(); + hashCode = (hashCode * 397) ^ UShort.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) UInt; + hashCode = (hashCode * 397) ^ ULong.GetHashCode(); + hashCode = (hashCode * 397) ^ Char.GetHashCode(); + hashCode = (hashCode * 397) ^ Float.GetHashCode(); + hashCode = (hashCode * 397) ^ Double.GetHashCode(); + hashCode = (hashCode * 397) ^ Decimal.GetHashCode(); + hashCode = (hashCode * 397) ^ Boolean.GetHashCode(); + hashCode = (hashCode * 397) ^ (String != null ? String.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ DateTime.GetHashCode(); + hashCode = (hashCode * 397) ^ (Exception != null ? Exception.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (int) Enum; + hashCode = (hashCode * 397) ^ Struct.GetHashCode(); + return hashCode; + } + } + + private bool Equals(CrossFrameworkClass other) + { + return Sbyte == other.Sbyte + && Short == other.Short + && Int == other.Int + && Long == other.Long + && Byte == other.Byte + && UShort == other.UShort + && UInt == other.UInt + && ULong == other.ULong + && Char == other.Char + && Math.Abs(Float - other.Float) < float.Epsilon + && Math.Abs(Double - other.Double) < double.Epsilon + && Decimal == other.Decimal + && Boolean == other.Boolean + && string.Equals(String, other.String) + && DateTime.Equals(other.DateTime) + // && Equals(Exception, other.Exception) + && Exception.Message == other.Exception.Message + && Enum == other.Enum + && Struct.Equals(other.Struct); + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/Generator/CrossFrameworkEnum.cs b/src/Hyperion.Tests/Generator/CrossFrameworkEnum.cs new file mode 100644 index 00000000..aaf0c112 --- /dev/null +++ b/src/Hyperion.Tests/Generator/CrossFrameworkEnum.cs @@ -0,0 +1,13 @@ +namespace Hyperion.Tests.Generator +{ + public enum CrossFrameworkEnum + { + ShortSword, + LongSword, + BastardSword, + Claymore, + Scimitar, + Yatagan, + Katana + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/Generator/CrossFrameworkInitializer.cs b/src/Hyperion.Tests/Generator/CrossFrameworkInitializer.cs new file mode 100644 index 00000000..dae3431f --- /dev/null +++ b/src/Hyperion.Tests/Generator/CrossFrameworkInitializer.cs @@ -0,0 +1,49 @@ +using System; + +namespace Hyperion.Tests.Generator +{ + public static class CrossFrameworkInitializer + { + public const string DefaultOutputPath = "../../../testfiles"; + + public static CrossFrameworkClass Init() + { + return new CrossFrameworkClass() + { + Exception = new Exception("Test message", new ArgumentNullException("param", "Cannot be null")), + DateTime = new DateTime(1944, 6, 6), // DDay + Enum = CrossFrameworkEnum.Yatagan, + String = "On June 6, 1944, more than 160,000 Allied troops landed along a 50-mile stretch of heavily-fortified French coastline", + Struct = new CrossFrameworkStruct() + { + Boolean = true, + Long = long.MaxValue, + Decimal = decimal.MinusOne, + Double = double.MaxValue, + Int = int.MaxValue, + Short = short.MaxValue, + ULong = ulong.MinValue, + Byte = byte.MaxValue, + Char = char.MaxValue, + Float = float.MinValue, + UShort = ushort.MinValue, + UInt = uint.MaxValue, + Sbyte = sbyte.MaxValue + }, + Decimal = decimal.MaxValue, + Float = float.MaxValue, + Long = long.MinValue, + Int = int.MinValue, + Double = double.Epsilon, + Char = char.MaxValue, + Byte = byte.MaxValue, + Sbyte = sbyte.MaxValue, + Short = short.MaxValue, + UInt = uint.MaxValue, + ULong = ulong.MaxValue, + UShort = ushort.MaxValue, + Boolean = true + }; + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/Generator/CrossFrameworkStruct.cs b/src/Hyperion.Tests/Generator/CrossFrameworkStruct.cs new file mode 100644 index 00000000..8bda1963 --- /dev/null +++ b/src/Hyperion.Tests/Generator/CrossFrameworkStruct.cs @@ -0,0 +1,83 @@ +using System; + +namespace Hyperion.Tests.Generator +{ + public struct CrossFrameworkStruct + { + public sbyte Sbyte { get; set; } + + public short Short { get; set; } + + public int Int { get; set; } + + public long Long { get; set; } + + public byte Byte { get; set; } + + public ushort UShort { get; set; } + + public uint UInt { get; set; } + + public ulong ULong { get; set; } + + public char Char { get; set; } + + public float Float { get; set; } + + public double Double { get; set; } + + public decimal Decimal { get; set; } + + public bool Boolean { get; set; } + + public override bool Equals(object obj) + { + if (!(obj is CrossFrameworkStruct)) + { + return false; + } + + var objectToCompare = (CrossFrameworkStruct)obj; + + return Equals(objectToCompare); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = Sbyte.GetHashCode(); + hashCode = (hashCode * 397) ^ Short.GetHashCode(); + hashCode = (hashCode * 397) ^ Int; + hashCode = (hashCode * 397) ^ Long.GetHashCode(); + hashCode = (hashCode * 397) ^ Byte.GetHashCode(); + hashCode = (hashCode * 397) ^ UShort.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) UInt; + hashCode = (hashCode * 397) ^ ULong.GetHashCode(); + hashCode = (hashCode * 397) ^ Char.GetHashCode(); + hashCode = (hashCode * 397) ^ Float.GetHashCode(); + hashCode = (hashCode * 397) ^ Double.GetHashCode(); + hashCode = (hashCode * 397) ^ Decimal.GetHashCode(); + hashCode = (hashCode * 397) ^ Boolean.GetHashCode(); + return hashCode; + } + } + + private bool Equals(CrossFrameworkStruct other) + { + return Sbyte == other.Sbyte + && Short == other.Short + && Int == other.Int + && Long == other.Long + && Byte == other.Byte + && UShort == other.UShort + && UInt == other.UInt + && ULong == other.ULong + && Char == other.Char + && Math.Abs(Float - other.Float) < float.Epsilon + && Math.Abs(Double - other.Double) < double.Epsilon + && Decimal == other.Decimal + && Boolean == other.Boolean; + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/Generator/Program.cs b/src/Hyperion.Tests/Generator/Program.cs new file mode 100644 index 00000000..c0ae7045 --- /dev/null +++ b/src/Hyperion.Tests/Generator/Program.cs @@ -0,0 +1,43 @@ +using System.IO; +using System.Reflection; +using System.Runtime.Versioning; +using System.Text.RegularExpressions; + +namespace Hyperion.Tests.Generator +{ + internal static class Program + { + private static readonly Serializer Serializer = new Serializer(); + private static readonly string FullFrameworkName = Assembly + .GetEntryAssembly()? + .GetCustomAttribute()? + .FrameworkName; + + private static readonly string FrameworkName = Regex.Replace(FullFrameworkName, "[^\\w\\._]", string.Empty); + + private static void Main(string[] args) + { + if (args.Length != 1 || args[0] != "generate") + { + return; + } + + string outputPath = args.Length == 2 ? args[1] : CrossFrameworkInitializer.DefaultOutputPath; + + if (!Directory.Exists(outputPath)) + { + Directory.CreateDirectory(outputPath); + } + + CrossFrameworkClass crossFrameworkClass = CrossFrameworkInitializer.Init(); + + string fileName = $"test_file_{FrameworkName.ToLowerInvariant()}.tf"; + string fullPath = Path.Combine(outputPath, fileName); + + using (var fileStream = new FileStream(fullPath, FileMode.Create)) + { + Serializer.Serialize(crossFrameworkClass, fileStream); + } + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/Hyperion.Tests.csproj b/src/Hyperion.Tests/Hyperion.Tests.csproj index f97c9736..8bebdc43 100644 --- a/src/Hyperion.Tests/Hyperion.Tests.csproj +++ b/src/Hyperion.Tests/Hyperion.Tests.csproj @@ -2,7 +2,11 @@ + Exe net461;netcoreapp2.1;netcoreapp3.0 + true + latest + Hyperion.Tests.Generator.Program diff --git a/src/Hyperion.Tests/Properties/launchSettings.json b/src/Hyperion.Tests/Properties/launchSettings.json new file mode 100644 index 00000000..39bea140 --- /dev/null +++ b/src/Hyperion.Tests/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Hyperion.Tests": { + "commandName": "Project", + "commandLineArgs": "generate" + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.0.tf b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.0.tf new file mode 100644 index 00000000..d5a25698 Binary files /dev/null and b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.0.tf differ diff --git a/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.1.tf b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.1.tf new file mode 100644 index 00000000..d5a25698 Binary files /dev/null and b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.1.tf differ diff --git a/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.2.tf b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.2.tf new file mode 100644 index 00000000..d5a25698 Binary files /dev/null and b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv2.2.tf differ diff --git a/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv3.0.tf b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv3.0.tf new file mode 100644 index 00000000..d5a25698 Binary files /dev/null and b/src/Hyperion.Tests/testfiles/test_file_.netcoreappversionv3.0.tf differ diff --git a/src/Hyperion.Tests/testfiles/test_file_.netframeworkversionv4.6.1.tf b/src/Hyperion.Tests/testfiles/test_file_.netframeworkversionv4.6.1.tf new file mode 100644 index 00000000..9e96ef28 Binary files /dev/null and b/src/Hyperion.Tests/testfiles/test_file_.netframeworkversionv4.6.1.tf differ diff --git a/src/Hyperion/Extensions/TypeEx.cs b/src/Hyperion/Extensions/TypeEx.cs index a2aa56f7..32f31f1e 100644 --- a/src/Hyperion/Extensions/TypeEx.cs +++ b/src/Hyperion/Extensions/TypeEx.cs @@ -118,11 +118,23 @@ private static Type GetTypeFromManifestName(Stream stream, DeserializerSession s return TypeNameLookup.GetOrAdd(byteArr, b => { var shortName = StringEx.FromUtf8Bytes(b.Bytes, 0, b.Bytes.Length); +#if NET45 + if (shortName.Contains("System.Private.CoreLib,%core%")) + { + shortName = shortName.Replace("System.Private.CoreLib,%core%", "mscorlib,%core%"); + } +#endif +#if NETSTANDARD + if (shortName.Contains("mscorlib,%core%")) + { + shortName = shortName.Replace("mscorlib,%core%", "System.Private.CoreLib,%core%"); + } +#endif + var typename = ToQualifiedAssemblyName(shortName); return Type.GetType(typename, true); }); } - public static Type GetTypeFromManifestFull(Stream stream, DeserializerSession session) { var type = GetTypeFromManifestName(stream, session); @@ -195,7 +207,7 @@ public static int GetTypeSize(this Type type) throw new NotSupportedException(); } - + private static readonly string CoreAssemblyQualifiedName = 1.GetType().AssemblyQualifiedName; private static readonly string CoreAssemblyName = GetCoreAssemblyName(); private static readonly Regex cleanAssemblyVersionRegex = new Regex( @@ -204,8 +216,7 @@ public static int GetTypeSize(this Type type) private static string GetCoreAssemblyName() { - var name = 1.GetType().AssemblyQualifiedName; - var part = name.Substring( name.IndexOf(", Version", StringComparison.Ordinal)); + var part = CoreAssemblyQualifiedName.Substring(CoreAssemblyQualifiedName.IndexOf(", Version", StringComparison.Ordinal)); return part; }