private static void SanityCheckBlob(object obj, TypeSerializableValue[] blobs)
        {
            // These types are unstable during serialization and produce different blobs.
            string name = obj.GetType().FullName;

            if (obj is WeakReference <Point> ||
                obj is Collections.Specialized.HybridDictionary ||
                obj is Color ||
                name == "System.Collections.SortedList+SyncSortedList" ||
                // Due to non-deterministic field ordering the types below will fail when using IL Emit-based Invoke.
                // The types above may also be failing for the same reason.
                // Remove these cases once https://github.com/dotnet/runtime/issues/46272 is fixed.
                name == "System.Collections.Comparer" ||
                name == "System.Collections.Hashtable" ||
                name == "System.Collections.SortedList" ||
                name == "System.Collections.Specialized.ListDictionary" ||
                name == "System.CultureAwareComparer" ||
                name == "System.Globalization.CompareInfo" ||
                name == "System.Net.Cookie" ||
                name == "System.Net.CookieCollection" ||
                name == "System.Net.CookieContainer")
            {
                return;
            }

            // The blobs aren't identical because of different implementations on Unix vs. Windows.
            if (obj is Bitmap ||
                obj is Icon ||
                obj is Metafile)
            {
                return;
            }

            // In most cases exceptions in Core have a different layout than in Desktop,
            // therefore we are skipping the string comparison of the blobs.
            if (obj is Exception)
            {
                return;
            }

            // Check if runtime generated blob is the same as the stored one
            int frameworkBlobNumber = blobs.GetPlatformIndex();

            if (frameworkBlobNumber < blobs.Length)
            {
                string runtimeBlob = BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full);

                string storedComparableBlob  = CreateComparableBlobInfo(blobs[frameworkBlobNumber].Base64Blob);
                string runtimeComparableBlob = CreateComparableBlobInfo(runtimeBlob);

                Assert.True(storedComparableBlob == runtimeComparableBlob,
                            $"The stored blob for type {obj.GetType().FullName} is outdated and needs to be updated.{Environment.NewLine}{Environment.NewLine}" +
                            $"-------------------- Stored blob ---------------------{Environment.NewLine}" +
                            $"Encoded: {blobs[frameworkBlobNumber].Base64Blob}{Environment.NewLine}" +
                            $"Decoded: {storedComparableBlob}{Environment.NewLine}{Environment.NewLine}" +
                            $"--------------- Runtime generated blob ---------------{Environment.NewLine}" +
                            $"Encoded: {runtimeBlob}{Environment.NewLine}" +
                            $"Decoded: {runtimeComparableBlob}");
            }
        }
        private static void ValidateAndRoundtrip(object obj, string[] blobs, bool isEqualityComparer)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The serializable object must not be null", nameof(obj));
            }

            if (blobs == null || blobs.Length == 0)
            {
                throw new ArgumentOutOfRangeException($"Type {obj} has no blobs to deserialize and test equality against. Blob: " +
                                                      BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full));
            }

            SanityCheckBlob(obj, blobs);

            foreach (string blob in blobs)
            {
                if (isEqualityComparer)
                {
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Simple));
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Full));
                }
                else
                {
                    CheckForAnyEquals(obj, BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Simple));
                    CheckForAnyEquals(obj, BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Full));
                }
            }
        }
        private static void ValidateAndRoundtrip(object obj, TypeSerializableValue[] blobs, bool isEqualityComparer)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The serializable object must not be null", nameof(obj));
            }

            if (blobs == null || blobs.Length == 0)
            {
                throw new ArgumentOutOfRangeException($"Type {obj} has no blobs to deserialize and test equality against. Blob: " +
                                                      BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full));
            }

            // Check if the passed in value in a serialization entry is assignable by the passed in type.
            if (obj is ISerializable customSerializableObj && HasObjectTypeIntegrity(customSerializableObj))
            {
                CheckObjectTypeIntegrity(customSerializableObj);
            }

            SanityCheckBlob(obj, blobs);

            // SqlException, ReflectionTypeLoadException and LicenseException aren't deserializable from Desktop --> Core.
            // Therefore we remove the second blob which is the one from Desktop.
            if (!PlatformDetection.IsFullFramework && (obj is SqlException || obj is ReflectionTypeLoadException || obj is LicenseException))
            {
                var tmpList = new List <TypeSerializableValue>(blobs);
                tmpList.RemoveAt(1);

                int index = tmpList.FindIndex(b => b.Platform.IsNetfxPlatform());
                if (index >= 0)
                {
                    tmpList.RemoveAt(index);
                }

                blobs = tmpList.ToArray();
            }

            // We store our framework blobs in index 1
            int platformBlobIndex = blobs.GetPlatformIndex();

            for (int i = 0; i < blobs.Length; i++)
            {
                // Check if the current blob is from the current running platform.
                bool isSamePlatform = i == platformBlobIndex;

                if (isEqualityComparer)
                {
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple));
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full));
                }
                else
                {
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple), isSamePlatform);
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full), isSamePlatform);
                }
            }
        }
        // Used for updating blobs in BinaryFormatterTestData.cs
        //[Fact]
        public void UpdateBlobs()
        {
            string testDataFilePath = GetTestDataFilePath();

            string[] coreTypeBlobs = SerializableEqualityComparers_MemberData()
                                     .Concat(SerializableObjects_MemberData())
                                     .Select(record => BinaryFormatterHelpers.ToBase64String(record[0]))
                                     .ToArray();

            var(numberOfBlobs, numberOfFoundBlobs, numberOfUpdatedBlobs) = UpdateCoreTypeBlobs(testDataFilePath, coreTypeBlobs);
            Console.WriteLine($"{numberOfBlobs} existing blobs" +
                              $"{Environment.NewLine}{numberOfFoundBlobs} found blobs with regex search" +
                              $"{Environment.NewLine}{numberOfUpdatedBlobs} updated blobs with regex replace");
        }
        private static void SanityCheckBlob(object obj, TypeSerializableValue[] blobs)
        {
            // These types are unstable during serialization and produce different blobs.
            if (obj is WeakReference <Point> ||
                obj is Collections.Specialized.HybridDictionary ||
                obj is Color ||
                obj.GetType().FullName == "System.Collections.SortedList+SyncSortedList")
            {
                return;
            }

            // The blobs aren't identical because of different implementations on Unix vs. Windows.
            if (obj is Bitmap ||
                obj is Icon ||
                obj is Metafile)
            {
                return;
            }

            // In most cases exceptions in Core have a different layout than in Desktop,
            // therefore we are skipping the string comparison of the blobs.
            if (obj is Exception)
            {
                return;
            }

            // Check if runtime generated blob is the same as the stored one
            int frameworkBlobNumber = blobs.GetPlatformIndex();

            if (frameworkBlobNumber < blobs.Length)
            {
                string runtimeBlob = BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full);

                string storedComparableBlob  = CreateComparableBlobInfo(blobs[frameworkBlobNumber].Base64Blob);
                string runtimeComparableBlob = CreateComparableBlobInfo(runtimeBlob);

                Assert.True(storedComparableBlob == runtimeComparableBlob,
                            $"The stored blob for type {obj.GetType().FullName} is outdated and needs to be updated.{Environment.NewLine}{Environment.NewLine}" +
                            $"-------------------- Stored blob ---------------------{Environment.NewLine}" +
                            $"Encoded: {blobs[frameworkBlobNumber].Base64Blob}{Environment.NewLine}" +
                            $"Decoded: {storedComparableBlob}{Environment.NewLine}{Environment.NewLine}" +
                            $"--------------- Runtime generated blob ---------------{Environment.NewLine}" +
                            $"Encoded: {runtimeBlob}{Environment.NewLine}" +
                            $"Decoded: {runtimeComparableBlob}");
            }
        }
        private static void ValidateAndRoundtrip(object obj, string[] blobs, bool isEqualityComparer)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The serializable object must not be null", nameof(obj));
            }

            if (blobs == null || blobs.Length == 0)
            {
                throw new ArgumentOutOfRangeException($"Type {obj} has no blobs to deserialize and test equality against. Blob: " +
                                                      BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full));
            }

            SanityCheckBlob(obj, blobs);

            // SqlException isn't deserializable from Desktop --> Core.
            // Therefore we remove the second blob which is the one from Desktop.
            if (!PlatformDetection.IsFullFramework && (obj is SqlException || obj is ReflectionTypeLoadException || obj is LicenseException))
            {
                var tmpList = new List <string>(blobs);
                tmpList.RemoveAt(1);
                blobs = tmpList.ToArray();
            }

            // We store our framework blobs in index 1
            int platformBlobIndex = PlatformDetection.IsFullFramework ? 1 : 0;

            for (int i = 0; i < blobs.Length; i++)
            {
                // Check if the current blob is from the current running platform.
                bool isSamePlatform = i == platformBlobIndex;

                if (isEqualityComparer)
                {
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Simple));
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Full));
                }
                else
                {
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Simple), isSamePlatform);
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Full), isSamePlatform);
                }
            }
        }
        private static void ValidateAndRoundtrip(object obj, string[] blobs, bool isEqualityComparer)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The serializable object must not be null", nameof(obj));
            }

            if (blobs == null || blobs.Length == 0)
            {
                throw new ArgumentOutOfRangeException($"Type {obj} has no blobs to deserialize and test equality against. Blob: " +
                                                      BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full));
            }

            SanityCheckBlob(obj, blobs);

            // SqlException isn't deserializable from Desktop --> Core.
            // Therefore we remove the second blob which is the one from Desktop.
            if (!PlatformDetection.IsFullFramework && (obj is SqlException || obj is ReflectionTypeLoadException || obj is LicenseException))
            {
                var tmpList = new List <string>(blobs);
                tmpList.RemoveAt(1);
                blobs = tmpList.ToArray();
            }

            foreach (string blob in blobs)
            {
                if (isEqualityComparer)
                {
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Simple));
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Full));
                }
                else
                {
                    CheckForAnyEquals(obj, BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Simple));
                    CheckForAnyEquals(obj, BinaryFormatterHelpers.FromBase64String(blob, FormatterAssemblyStyle.Full));
                }
            }
        }
        private static void SanityCheckBlob(object obj, string[] blobs)
        {
            // These types are unstable during serialization and produce different blobs.
            if (obj is WeakReference <Point> ||
                obj is Collections.Specialized.HybridDictionary ||
                obj is TimeZoneInfo.AdjustmentRule)
            {
                return;
            }

            // In most cases exceptions in Core have a different layout than in Desktop,
            // therefore we are skipping the string comparison of the blobs.
            if (obj is Exception)
            {
                return;
            }

            // Check if runtime generated blob is the same as the stored one
            int frameworkBlobNumber = PlatformDetection.IsFullFramework ? 1 : 0;

            if (frameworkBlobNumber < blobs.Length)
            {
                string runtimeBlob = BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full);

                string storedComparableBlob  = CreateComparableBlobInfo(blobs[frameworkBlobNumber]);
                string runtimeComparableBlob = CreateComparableBlobInfo(runtimeBlob);

                Assert.True(storedComparableBlob == runtimeComparableBlob,
                            $"The stored blob for type {obj.GetType().FullName} is outdated and needs to be updated.{Environment.NewLine}{Environment.NewLine}" +
                            $"-------------------- Stored blob ---------------------{Environment.NewLine}" +
                            $"Encoded: {blobs[frameworkBlobNumber]}{Environment.NewLine}" +
                            $"Decoded: {storedComparableBlob}{Environment.NewLine}{Environment.NewLine}" +
                            $"--------------- Runtime generated blob ---------------{Environment.NewLine}" +
                            $"Encoded: {runtimeBlob}{Environment.NewLine}" +
                            $"Decoded: {runtimeComparableBlob}");
            }
        }
        private static void ValidateAndRoundtrip(object obj, TypeSerializableValue[] blobs, bool isEqualityComparer)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The serializable object must not be null", nameof(obj));
            }

            if (blobs == null || blobs.Length == 0)
            {
                throw new ArgumentOutOfRangeException($"Type {obj} has no blobs to deserialize and test equality against. Blob: " +
                                                      BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full));
            }

            // Check if the passed in value in a serialization entry is assignable by the passed in type.
            if (obj is ISerializable customSerializableObj && HasObjectTypeIntegrity(customSerializableObj))
            {
                CheckObjectTypeIntegrity(customSerializableObj);
            }

            // TimeZoneInfo objects have three properties (DisplayName, StandardName, DaylightName)
            // that are localized.  Since the blobs were generated from the invariant culture, they
            // will have English strings embedded.  Thus, we can only test them against English
            // language cultures or the invariant culture.
            if (obj is TimeZoneInfo && (
                    CultureInfo.CurrentUICulture.TwoLetterISOLanguageName != "en" ||
                    CultureInfo.CurrentUICulture.Name.Length != 0))
            {
                return;
            }

            SanityCheckBlob(obj, blobs);

            // ReflectionTypeLoadException and LicenseException aren't deserializable from Desktop --> Core.
            // Therefore we remove the second blob which is the one from Desktop.
            if (!PlatformDetection.IsNetFramework && (obj is ReflectionTypeLoadException || obj is LicenseException))
            {
                var tmpList = new List <TypeSerializableValue>(blobs);
                tmpList.RemoveAt(1);

                int index = tmpList.FindIndex(b => b.Platform.ToString().StartsWith("netfx"));
                if (index >= 0)
                {
                    tmpList.RemoveAt(index);
                }

                blobs = tmpList.ToArray();
            }

            // We store our framework blobs in index 1
            int platformBlobIndex = blobs.GetPlatformIndex();

            for (int i = 0; i < blobs.Length; i++)
            {
                // Check if the current blob is from the current running platform.
                bool isSamePlatform = i == platformBlobIndex;

                if (isEqualityComparer)
                {
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple));
                    ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full));
                }
                else
                {
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple), isSamePlatform);
                    EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full), isSamePlatform);
                }
            }
        }
        public void NullableComparersRoundtrip(string expectedType, object obj)
        {
            string serialized = BinaryFormatterHelpers.ToBase64String(obj);

            Assert.Equal(expectedType, BinaryFormatterHelpers.FromBase64String(serialized).GetType().Name);
        }