diff --git a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs index 71c7bb43877c..3edd9283d7fb 100644 --- a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs +++ b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs @@ -4,12 +4,18 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.Tracing; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Runtime.Remoting.Messaging; using System.Runtime.Serialization.Formatters.Binary; +using System.Security; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Runtime.Serialization.Formatters.Tests @@ -39,6 +45,9 @@ public static IEnumerable SerializableObjects() yield return float.MaxValue; yield return double.MinValue; yield return double.MaxValue; + yield return decimal.MinValue; + yield return decimal.MaxValue; + yield return decimal.MinusOne; yield return true; yield return false; yield return ""; @@ -58,13 +67,27 @@ public static IEnumerable SerializableObjects() yield return (StructWithIntField?)new StructWithIntField() { X = 42 }; // Other core serializable types + yield return IntPtr.Zero; + yield return UIntPtr.Zero; + yield return DateTime.Now; + yield return DateTimeOffset.Now; + yield return DateTimeKind.Local; yield return TimeSpan.FromDays(7); yield return new Version(1, 2, 3, 4); - yield return Tuple.Create(1, "2", Tuple.Create(3.4)); yield return new Guid("0CACAA4D-C6BD-420A-B660-2F557337CA89"); yield return new AttributeUsageAttribute(AttributeTargets.Class); yield return new List(); yield return new List() { 1, 2, 3, 4, 5 }; + yield return new Dictionary() { { 1, "test" }, { 2, "another test" } }; + yield return Tuple.Create(1); + yield return Tuple.Create(1, "2"); + yield return Tuple.Create(1, "2", 3u); + yield return Tuple.Create(1, "2", 3u, 4L); + yield return Tuple.Create(1, "2", 3u, 4L, 5.6); + yield return Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f); + yield return Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m); + yield return Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10)); + yield return new KeyValuePair(42, 84); // Arrays of primitive types yield return Enumerable.Range(0, 256).Select(i => (byte)i).ToArray(); @@ -112,6 +135,10 @@ public static IEnumerable SerializableObjects() arr.SetValue("hello", new[] { 3, 5 }); yield return arr; + //// Various globalization types + //yield return CultureInfo.CurrentCulture; + //yield return CultureInfo.InvariantCulture; + // Custom object var sealedObjectWithIntStringFields = new SealedObjectWithIntStringFields(); yield return sealedObjectWithIntStringFields; @@ -190,14 +217,6 @@ public static IEnumerable NonSerializableObjects() yield return new NonSerializableClass(); yield return new SerializableClassWithBadField(); yield return new object[] { 1, 2, 3, new NonSerializableClass() }; - - // TODO: Move these to the serializable category when enabled in the runtime - var e = new OperationCanceledException(); - yield return e; - try { throw e; } catch { } yield return e; - yield return new Dictionary() { { 1, "test" }, { 2, "another test" } }; - yield return IntPtr.Zero; - yield return UIntPtr.Zero; } public static IEnumerable ValidateBasicObjectsRoundtrip_MemberData() @@ -289,6 +308,143 @@ public void SameObjectRepeatedInArray() } } + public static IEnumerable SerializableExceptions() + { + yield return new object[] { new AbandonedMutexException() }; + yield return new object[] { new AggregateException(new FieldAccessException(), new MemberAccessException()) }; + yield return new object[] { new AmbiguousMatchException() }; + yield return new object[] { new ArgumentException("message", "paramName") }; + yield return new object[] { new ArgumentNullException("paramName") }; + yield return new object[] { new ArgumentOutOfRangeException("paramName", 42, "message") }; + yield return new object[] { new ArithmeticException() }; + yield return new object[] { new ArrayTypeMismatchException("message") }; + yield return new object[] { new BadImageFormatException("message", "filename") }; + yield return new object[] { new COMException() }; + //yield return new object[] { new CultureNotFoundException() }; + yield return new object[] { new DataMisalignedException("message") }; + yield return new object[] { new DecoderFallbackException() }; + yield return new object[] { new DirectoryNotFoundException() }; + yield return new object[] { new DivideByZeroException() }; + yield return new object[] { new DllNotFoundException() }; + yield return new object[] { new EncoderFallbackException() }; + yield return new object[] { new EndOfStreamException() }; + yield return new object[] { new EventSourceException() }; + yield return new object[] { new Exception("message") }; + yield return new object[] { new FieldAccessException("message", new FieldAccessException()) }; + yield return new object[] { new FileLoadException() }; + yield return new object[] { new FileNotFoundException() }; + yield return new object[] { new FormatException("message") }; + yield return new object[] { new IndexOutOfRangeException() }; + yield return new object[] { new InsufficientExecutionStackException() }; + yield return new object[] { new InvalidCastException() }; + yield return new object[] { new InvalidComObjectException() }; + yield return new object[] { new InvalidOleVariantTypeException() }; + yield return new object[] { new InvalidOperationException() }; + yield return new object[] { new InvalidProgramException() }; + yield return new object[] { new InvalidTimeZoneException() }; + yield return new object[] { new IOException() }; + yield return new object[] { new KeyNotFoundException() }; + yield return new object[] { new LockRecursionException() }; + yield return new object[] { new MarshalDirectiveException() }; + yield return new object[] { new MemberAccessException() }; + yield return new object[] { new MethodAccessException() }; + yield return new object[] { new MissingFieldException() }; + yield return new object[] { new MissingMemberException() }; + yield return new object[] { new NotImplementedException() }; + yield return new object[] { new NotSupportedException() }; + yield return new object[] { new NullReferenceException() }; + yield return new object[] { new ObjectDisposedException("objectName") }; + yield return new object[] { new OperationCanceledException(new CancellationTokenSource().Token) }; + yield return new object[] { new OutOfMemoryException() }; + yield return new object[] { new OverflowException() }; + yield return new object[] { new PathTooLongException() }; + yield return new object[] { new PlatformNotSupportedException() }; + yield return new object[] { new RankException() }; + yield return new object[] { new SafeArrayRankMismatchException() }; + yield return new object[] { new SafeArrayTypeMismatchException() }; + yield return new object[] { new SecurityException() }; + yield return new object[] { new SEHException() }; + yield return new object[] { new SemaphoreFullException() }; + yield return new object[] { new SerializationException() }; + yield return new object[] { new SynchronizationLockException() }; + yield return new object[] { new TargetInvocationException("message", new Exception()) }; + yield return new object[] { new TargetParameterCountException() }; + yield return new object[] { new TaskCanceledException(Task.CompletedTask) }; + yield return new object[] { new TaskSchedulerException() }; + yield return new object[] { new TimeoutException() }; + yield return new object[] { new TypeAccessException() }; + yield return new object[] { new TypeInitializationException(typeof(string).FullName, new Exception()) }; + yield return new object[] { new TypeLoadException() }; + yield return new object[] { new UnauthorizedAccessException("message", new ArgumentNullException()) }; + yield return new object[] { new VerificationException() }; + yield return new object[] { new WaitHandleCannotBeOpenedException() }; + } + + [Theory] + [MemberData(nameof(SerializableExceptions))] + public void Roundtrip_Exceptions(Exception expected) + { + for (int i = 0; i < 2; i++) + { + Exception actual = FormatterClone(expected); + + Assert.Equal(expected.StackTrace, actual.StackTrace); + Assert.Equal(expected.Data, actual.Data); + Assert.Equal(expected.Message, actual.Message); + Assert.Equal(expected.Source, actual.Source); + Assert.Equal(expected.ToString(), actual.ToString()); + Assert.Equal(expected.HResult, actual.HResult); + + if (i == 0) + { + try { throw expected; } catch { } + } + } + } + + private static int Identity(int i) => i; + + [Fact] + public void Roundtrip_Delegates_NoTarget() + { + Func expected = Identity; + Assert.Null(expected.Target); + + Func actual = FormatterClone(expected); + + Assert.NotSame(expected, actual); + Assert.Same(expected.GetMethodInfo(), actual.GetMethodInfo()); + Assert.Equal(expected(42), actual(42)); + } + + [Fact] + public void Roundtrip_Delegates_Target() + { + var owsam = new ObjectWithStateAndMethod { State = 42 }; + Func expected = owsam.GetState; + Assert.Same(owsam, expected.Target); + + Func actual = FormatterClone(expected); + + Assert.NotSame(expected, actual); + Assert.NotSame(expected.Target, actual.Target); + Assert.Equal(expected(), actual()); + } + + public static IEnumerable SerializableObjectsWithFuncOfObjectToCompare() + { + object target = 42; + yield return new object[] { new Random(), new Func(o => ((Random)o).Next()) }; + } + + [Theory] + [MemberData(nameof(SerializableObjectsWithFuncOfObjectToCompare))] + public void Roundtrip_ObjectsWithComparers(object obj, Func getResult) + { + object actual = FormatterClone(obj); + Assert.Equal(getResult(obj), getResult(actual)); + } + public static IEnumerable ValidateNonSerializableTypes_MemberData() { foreach (object obj in NonSerializableObjects()) @@ -524,7 +680,7 @@ public static IEnumerable Deserialize_FuzzInput_MemberData() const int FuzzingsPerObject = 20; for (int i = 0; i < FuzzingsPerObject; i++) { - yield return new object[] { obj, rand }; + yield return new object[] { obj, rand, i }; } } } @@ -532,7 +688,7 @@ public static IEnumerable Deserialize_FuzzInput_MemberData() [OuterLoop] [Theory] [MemberData(nameof(Deserialize_FuzzInput_MemberData))] - public void Deserialize_FuzzInput(object obj, Random rand) + public void Deserialize_FuzzInput(object obj, Random rand, int fuzzTrial) { // Get the serialized data for the object var f = new BinaryFormatter(); @@ -562,6 +718,7 @@ public void Deserialize_FuzzInput(object obj, Random rand) catch (OverflowException) { } catch (NullReferenceException) { } catch (SerializationException) { } + catch (TargetInvocationException) { } } [Fact] diff --git a/src/System.Runtime.Serialization.Formatters/tests/SerializationTypes.cs b/src/System.Runtime.Serialization.Formatters/tests/SerializationTypes.cs index 9751baa5940d..898c485ace36 100644 --- a/src/System.Runtime.Serialization.Formatters/tests/SerializationTypes.cs +++ b/src/System.Runtime.Serialization.Formatters/tests/SerializationTypes.cs @@ -404,6 +404,13 @@ public class Version2ClassWithOptionalField public object Value; } + [Serializable] + public class ObjectWithStateAndMethod + { + public int State; + public int GetState() => State; + } + internal sealed class ObjectReferenceEqualityComparer : IEqualityComparer { public new bool Equals(object x, object y) => ReferenceEquals(x, y);