From 4e93c2e62e826124d9bcc1b500061f8872bd495e Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 28 Jan 2017 20:08:20 +1100 Subject: [PATCH 1/4] System.Lazy regression tests This is a prelude to an alternative Lazy implementation in a PR at https://github.com/dotnet/coreclr/pull/8963 --- .../tests/System.Runtime.Tests.csproj | 1 + .../tests/System/LazyTests.regression.cs | 334 ++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 src/System.Runtime/tests/System/LazyTests.regression.cs diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj index 0f015f9a9867..da4f73326ae3 100644 --- a/src/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj @@ -79,6 +79,7 @@ + diff --git a/src/System.Runtime/tests/System/LazyTests.regression.cs b/src/System.Runtime/tests/System/LazyTests.regression.cs new file mode 100644 index 000000000000..0c6075f71514 --- /dev/null +++ b/src/System.Runtime/tests/System/LazyTests.regression.cs @@ -0,0 +1,334 @@ +using System.Reflection; +using System.Threading; +using Xunit; + +namespace System +{ + /// + /// This regression suite was designed for testing of a replacement for the original Lazy implementation. + /// It does contain some overlap with the existing tests, but I feel that it is still of worth to keep + /// the original suite as well as this one. These tests were written with the express purpose of testing + /// that the implementation conforms to the existing implementation, rather than to specification. + /// The two reasons obviously have major overlap (obviously), but leads to the flavour of this suite + /// being rather dense and repeditive, which for regression I feel is suitable. + /// + public static partial class LazyTests + { + class MyException + : Exception + { + public int Value { get; } + + public MyException(int value) + { + Value = value; + } + } + + public class Simple + { + public int Value { get; } + + public Simple(int value) + { + Value = value; + } + + public Simple() + { + Value = 42; + } + } + + private static void CheckValueIs42(Lazy lazy) + { + Assert.False(lazy.IsValueCreated); + Assert.Equal(lazy.Value, 42); + Assert.True(lazy.IsValueCreated); + } + + private static void CheckValueIs42(Lazy lazy) + { + Assert.False(lazy.IsValueCreated); + Assert.Equal(lazy.Value.Value, 42); + Assert.True(lazy.IsValueCreated); + } + + [Fact] + public static void TrivialBaselineCheck() + { + CheckValueIs42(new Lazy(() => 42)); + CheckValueIs42(new Lazy(() => 42, true)); + CheckValueIs42(new Lazy(() => 42, false)); + CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.ExecutionAndPublication)); + CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.None)); + CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.PublicationOnly)); + + CheckValueIs42(new Lazy()); + CheckValueIs42(new Lazy(true)); + CheckValueIs42(new Lazy(false)); + CheckValueIs42(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); + CheckValueIs42(new Lazy(LazyThreadSafetyMode.None)); + CheckValueIs42(new Lazy(LazyThreadSafetyMode.PublicationOnly)); + CheckValueIs42(new Lazy(() => new Simple(42))); + CheckValueIs42(new Lazy(() => new Simple(42), true)); + CheckValueIs42(new Lazy(() => new Simple(42), false)); + CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.ExecutionAndPublication)); + CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.None)); + CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.PublicationOnly)); + } + + public class SimpleException + { + public SimpleException() : this(99) { } + + public SimpleException(int value) + { + throw new MyException(value); + } + } + + private static void CheckException(Type expected, Lazy lazy) + { + Exception e = null; + try + { + var t = lazy.Value; + } + catch (Exception ex) + { + e = ex; + } + Assert.NotNull(e); + Assert.Same(expected, e.GetType()); + } + + [Fact] + public static void CheckExceptions() + { + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); })); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, true)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, false)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); + + // These functions, possibly unintuitively, return a TargetInvocationException + CheckException(typeof(TargetInvocationException), new Lazy()); + CheckException(typeof(TargetInvocationException), new Lazy(true)); + CheckException(typeof(TargetInvocationException), new Lazy(false)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.None)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.PublicationOnly)); + + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99))); + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), true)); + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), false)); + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.None)); + CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.PublicationOnly)); + } + + private static void SameException(Lazy x) + { + Exception first = null; + try + { + var _ = x.Value; + } + catch (Exception thrown1) + { + first = thrown1; + } + Assert.NotNull(first); + + try + { + var _ = x.Value; + } + catch (MyException thrown2) + { + Assert.Same(first, thrown2); + } + } + + private static void DifferentException(Lazy x) + { + Exception first = null; + try + { + var _ = x.Value; + } + catch (Exception thrown1) + { + first = thrown1; + } + Assert.NotNull(first); + + Exception second = null; + try + { + var _ = x.Value; + } + catch (Exception thrown2) + { + second = thrown2; + } + Assert.NotNull(second); + + Assert.NotEqual(first, second); + } + + [Fact] + public static void SameOrDifferentException() + { + SameException(new Lazy(() => { throw new MyException(99); })); + SameException(new Lazy(() => { throw new MyException(99); }, true)); + SameException(new Lazy(() => { throw new MyException(99); }, false)); + SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); + SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); + + DifferentException(new Lazy()); + DifferentException(new Lazy(true)); + DifferentException(new Lazy(false)); + DifferentException(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); + DifferentException(new Lazy(LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(LazyThreadSafetyMode.PublicationOnly)); + + SameException(new Lazy(() => new SimpleException(99))); + SameException(new Lazy(() => new SimpleException(99), true)); + SameException(new Lazy(() => new SimpleException(99), false)); + SameException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.ExecutionAndPublication)); + SameException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.PublicationOnly)); + } + + private static void MultipleCallsToIntValue(Lazy lazy, ref int counter, int expected) + { + counter = 0; + var result = 0; + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + Assert.Equal(result, expected); + } + + private static void MultipleCallsToObjectValue(Lazy lazy, ref int counter, int? expected) + { + counter = 0; + var result = default(Simple); + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + if (expected == null) + Assert.Null(result); + else + Assert.Equal(result.Value, expected.Value); + } + + [Fact] + public static void MultipleValueCalls() + { + var counter = default(int); // set in test function + + var fint = new Func (() => { if (++counter < 5) throw new MyException(42); else return counter; }); + var fobj = new Func(() => { if (++counter < 5) throw new MyException(42); else return new Simple(counter); }); + + MultipleCallsToIntValue(new Lazy(fint), ref counter, 0); + MultipleCallsToIntValue(new Lazy(fint, true), ref counter, 0); + MultipleCallsToIntValue(new Lazy(fint, false), ref counter, 0); + MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, 0); + MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.None), ref counter, 0); + MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.PublicationOnly), ref counter, 5); + + MultipleCallsToObjectValue(new Lazy(fobj), ref counter, null); + MultipleCallsToObjectValue(new Lazy(fobj, true), ref counter, null); + MultipleCallsToObjectValue(new Lazy(fobj, false), ref counter, null); + MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, null); + MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.None), ref counter, null); + MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.PublicationOnly), ref counter, 5); + } + + class SimpleConstructor + { + public static int counter = 0; + public static int getValue() + { + if (++counter < 5) + throw new MyException(42); + else + return counter; + } + + public int Value { get; } + + public SimpleConstructor() + { + Value = getValue(); + } + } + + private static void MultipleCallsToConstructor(Lazy lazy, int? expected) + { + SimpleConstructor.counter = 0; + var result = default(SimpleConstructor); + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + if (expected == null) + Assert.Null(result); + else + Assert.Equal(result.Value, expected.Value); + } + + [Fact] + public static void MultipleCallsToExceptionThrowingConstructor() + { + MultipleCallsToConstructor(new Lazy(), 5); + MultipleCallsToConstructor(new Lazy(true), 5); + MultipleCallsToConstructor(new Lazy(false), 5); + MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication), 5); + MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.None), 5); + MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.PublicationOnly), 5); + } + + private static void CheckForInvalidOperationException(ref Lazy x, Lazy lazy) + { + x = lazy; + + var correct = false; + try + { + var _ = lazy.Value; + } + catch (InvalidOperationException) + { + correct = true; + } + Assert.True(correct); + } + + [Fact] + public static void LazyRecursion() + { + Lazy x = null; + Func f = () => x.Value; + + CheckForInvalidOperationException(ref x, new Lazy(f)); + CheckForInvalidOperationException(ref x, new Lazy(f, true)); + CheckForInvalidOperationException(ref x, new Lazy(f, false)); + CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.ExecutionAndPublication)); + CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.None)); + + // this just stackoverflows in current and new implementation + // CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.PublicationOnly)); + } + } +} From 75ca36cff62c0acde7ecca5f910507b58daa0f70 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 5 Feb 2017 15:26:52 +1100 Subject: [PATCH 2/4] Consolidated tests; added serialization test. --- .../tests/System.Runtime.Tests.csproj | 1 - src/System.Runtime/tests/System/LazyTests.cs | 281 ++++++++++++++- .../tests/System/LazyTests.regression.cs | 334 ------------------ 3 files changed, 275 insertions(+), 341 deletions(-) delete mode 100644 src/System.Runtime/tests/System/LazyTests.regression.cs diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj index da4f73326ae3..0f015f9a9867 100644 --- a/src/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj @@ -79,7 +79,6 @@ - diff --git a/src/System.Runtime/tests/System/LazyTests.cs b/src/System.Runtime/tests/System/LazyTests.cs index 1dc7bdcf5546..92dd142a051f 100644 --- a/src/System.Runtime/tests/System/LazyTests.cs +++ b/src/System.Runtime/tests/System/LazyTests.cs @@ -3,6 +3,9 @@ // See the LICENSE file in the project root for more information. using System.Threading; +using System.Reflection; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; using Xunit; namespace System.Tests @@ -103,17 +106,283 @@ public static void ToString_DoesntForceAllocation() Assert.Equal("1", lazy.ToString()); } + private static void Value_Invalid_Impl(ref Lazy x, Lazy lazy) + { + x = lazy; + Assert.Throws(() => { var dummy = lazy.Value; }); + } + [Fact] public static void Value_Invalid() { - string lazilyAllocatedValue = "abc"; + Lazy x = null; + Func f = () => x.Value; + + Value_Invalid_Impl(ref x, new Lazy(f)); + Value_Invalid_Impl(ref x, new Lazy(f, true)); + Value_Invalid_Impl(ref x, new Lazy(f, false)); + Value_Invalid_Impl(ref x, new Lazy(f, LazyThreadSafetyMode.ExecutionAndPublication)); + Value_Invalid_Impl(ref x, new Lazy(f, LazyThreadSafetyMode.None)); + + // When used with LazyThreadSafetyMode.PublicationOnly this causes a stack overflow + // Value_Invalid_Impl(ref x, new Lazy(f, LazyThreadSafetyMode.PublicationOnly)); + } + + class InitiallyExceptionThrowingCtor + { + public static int counter = 0; + public static int getValue() + { + if (++counter < 5) + throw new Exception(); + else + return counter; + } + + public int Value { get; } + + public InitiallyExceptionThrowingCtor() + { + Value = getValue(); + } + } + + private static void Ctor_ExceptionRecovery_Impl(Lazy lazy, int? expected) + { + InitiallyExceptionThrowingCtor.counter = 0; + var result = default(InitiallyExceptionThrowingCtor); + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + if (expected == null) + Assert.Null(result); + else + Assert.Equal(result.Value, expected.Value); + } - int x = 0; - Lazy lazy = null; - lazy = new Lazy(() => x++ < 5 ? lazy.Value : "Test", true); + [Fact] + public static void Ctor_ExceptionRecovery() + { + Ctor_ExceptionRecovery_Impl(new Lazy(), 5); + Ctor_ExceptionRecovery_Impl(new Lazy(true), 5); + Ctor_ExceptionRecovery_Impl(new Lazy(false), 5); + Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication), 5); + Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.None), 5); + Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.PublicationOnly), 5); + } - Assert.Throws(() => lazilyAllocatedValue = lazy.Value); - Assert.Equal("abc", lazilyAllocatedValue); + private static void Value_ExceptionRecovery_IntImpl(Lazy lazy, ref int counter, int expected) + { + counter = 0; + var result = 0; + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + Assert.Equal(result, expected); + } + + private static void Value_ExceptionRecovery_StringImpl(Lazy lazy, ref int counter, string expected) + { + counter = 0; + var result = default(string); + for (var i = 0; i < 10; ++i) + { + try { result = lazy.Value; } catch (Exception) { } + } + if (expected == null) + Assert.Null(result); + else + Assert.Equal(result, expected); + } + + [Fact] + public static void Value_ExceptionRecovery() + { + var counter = default(int); // set in test function + + var fint = new Func (() => { if (++counter < 5) throw new Exception(); else return counter; }); + var fobj = new Func(() => { if (++counter < 5) throw new Exception(); else return counter.ToString(); }); + + Value_ExceptionRecovery_IntImpl(new Lazy(fint), ref counter, 0); + Value_ExceptionRecovery_IntImpl(new Lazy(fint, true), ref counter, 0); + Value_ExceptionRecovery_IntImpl(new Lazy(fint, false), ref counter, 0); + Value_ExceptionRecovery_IntImpl(new Lazy(fint, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, 0); + Value_ExceptionRecovery_IntImpl(new Lazy(fint, LazyThreadSafetyMode.None), ref counter, 0); + Value_ExceptionRecovery_IntImpl(new Lazy(fint, LazyThreadSafetyMode.PublicationOnly), ref counter, 5); + + Value_ExceptionRecovery_StringImpl(new Lazy(fobj), ref counter, null); + Value_ExceptionRecovery_StringImpl(new Lazy(fobj, true), ref counter, null); + Value_ExceptionRecovery_StringImpl(new Lazy(fobj, false), ref counter, null); + Value_ExceptionRecovery_StringImpl(new Lazy(fobj, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, null); + Value_ExceptionRecovery_StringImpl(new Lazy(fobj, LazyThreadSafetyMode.None), ref counter, null); + Value_ExceptionRecovery_StringImpl(new Lazy(fobj, LazyThreadSafetyMode.PublicationOnly), ref counter, 5.ToString()); + } + + class MyException + : Exception + { + public int Value { get; } + + public MyException(int value) + { + Value = value; + } + } + + public class ExceptionInCtor + { + public ExceptionInCtor() : this(99) { } + + public ExceptionInCtor(int value) + { + throw new MyException(value); + } + } + + private static void CheckException(Type expected, Lazy lazy) + { + Exception e = null; + try + { + var t = lazy.Value; + } + catch (Exception ex) + { + e = ex; + } + Assert.NotNull(e); + Assert.Same(expected, e.GetType()); + } + + [Fact] + public static void CheckExceptions() + { + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); })); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, true)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, false)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); + CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); + + CheckException(typeof(TargetInvocationException), new Lazy()); + CheckException(typeof(TargetInvocationException), new Lazy(true)); + CheckException(typeof(TargetInvocationException), new Lazy(false)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.None)); + CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.PublicationOnly)); + + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99))); + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), true)); + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), false)); + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication)); + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None)); + CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly)); + } + + private static void SameException(Lazy x) + { + Exception first = null; + try + { + var _ = x.Value; + } + catch (Exception thrown1) + { + first = thrown1; + } + Assert.NotNull(first); + + try + { + var _ = x.Value; + } + catch (MyException thrown2) + { + Assert.Same(first, thrown2); + } + } + + private static void DifferentException(Lazy x) + { + Exception first = null; + try + { + var _ = x.Value; + } + catch (Exception thrown1) + { + first = thrown1; + } + Assert.NotNull(first); + + Exception second = null; + try + { + var _ = x.Value; + } + catch (Exception thrown2) + { + second = thrown2; + } + Assert.NotNull(second); + + Assert.NotEqual(first, second); + } + + [Fact] + public static void SameOrDifferentException() + { + SameException(new Lazy(() => { throw new MyException(99); })); + SameException(new Lazy(() => { throw new MyException(99); }, true)); + SameException(new Lazy(() => { throw new MyException(99); }, false)); + SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); + SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); + + DifferentException(new Lazy()); + DifferentException(new Lazy(true)); + DifferentException(new Lazy(false)); + DifferentException(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); + DifferentException(new Lazy(LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(LazyThreadSafetyMode.PublicationOnly)); + + SameException(new Lazy(() => new ExceptionInCtor(99))); + SameException(new Lazy(() => new ExceptionInCtor(99), true)); + SameException(new Lazy(() => new ExceptionInCtor(99), false)); + SameException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication)); + SameException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None)); + + DifferentException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly)); + } + + [Fact] + static void Serialization_ValueType() + { + var stream = new MemoryStream(); + var formatter = new BinaryFormatter(); + formatter.Serialize(stream, new Lazy(() => 42)); + stream.Seek(0, SeekOrigin.Begin); + + var fortytwo = (Lazy)formatter.Deserialize(stream); + Assert.True(fortytwo.IsValueCreated); + Assert.Equal(fortytwo.Value, 42); + } + + [Fact] + static void Serialization_RefType() + { + var stream = new MemoryStream(); + var formatter = new BinaryFormatter(); + formatter.Serialize(stream, new Lazy(() => "42")); + stream.Seek(0, SeekOrigin.Begin); + + var fortytwo = (Lazy)formatter.Deserialize(stream); + Assert.True(fortytwo.IsValueCreated); + Assert.Equal(fortytwo.Value, "42"); } [Theory] diff --git a/src/System.Runtime/tests/System/LazyTests.regression.cs b/src/System.Runtime/tests/System/LazyTests.regression.cs deleted file mode 100644 index 0c6075f71514..000000000000 --- a/src/System.Runtime/tests/System/LazyTests.regression.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System.Reflection; -using System.Threading; -using Xunit; - -namespace System -{ - /// - /// This regression suite was designed for testing of a replacement for the original Lazy implementation. - /// It does contain some overlap with the existing tests, but I feel that it is still of worth to keep - /// the original suite as well as this one. These tests were written with the express purpose of testing - /// that the implementation conforms to the existing implementation, rather than to specification. - /// The two reasons obviously have major overlap (obviously), but leads to the flavour of this suite - /// being rather dense and repeditive, which for regression I feel is suitable. - /// - public static partial class LazyTests - { - class MyException - : Exception - { - public int Value { get; } - - public MyException(int value) - { - Value = value; - } - } - - public class Simple - { - public int Value { get; } - - public Simple(int value) - { - Value = value; - } - - public Simple() - { - Value = 42; - } - } - - private static void CheckValueIs42(Lazy lazy) - { - Assert.False(lazy.IsValueCreated); - Assert.Equal(lazy.Value, 42); - Assert.True(lazy.IsValueCreated); - } - - private static void CheckValueIs42(Lazy lazy) - { - Assert.False(lazy.IsValueCreated); - Assert.Equal(lazy.Value.Value, 42); - Assert.True(lazy.IsValueCreated); - } - - [Fact] - public static void TrivialBaselineCheck() - { - CheckValueIs42(new Lazy(() => 42)); - CheckValueIs42(new Lazy(() => 42, true)); - CheckValueIs42(new Lazy(() => 42, false)); - CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.ExecutionAndPublication)); - CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.None)); - CheckValueIs42(new Lazy(() => 42, LazyThreadSafetyMode.PublicationOnly)); - - CheckValueIs42(new Lazy()); - CheckValueIs42(new Lazy(true)); - CheckValueIs42(new Lazy(false)); - CheckValueIs42(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); - CheckValueIs42(new Lazy(LazyThreadSafetyMode.None)); - CheckValueIs42(new Lazy(LazyThreadSafetyMode.PublicationOnly)); - CheckValueIs42(new Lazy(() => new Simple(42))); - CheckValueIs42(new Lazy(() => new Simple(42), true)); - CheckValueIs42(new Lazy(() => new Simple(42), false)); - CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.ExecutionAndPublication)); - CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.None)); - CheckValueIs42(new Lazy(() => new Simple(42), LazyThreadSafetyMode.PublicationOnly)); - } - - public class SimpleException - { - public SimpleException() : this(99) { } - - public SimpleException(int value) - { - throw new MyException(value); - } - } - - private static void CheckException(Type expected, Lazy lazy) - { - Exception e = null; - try - { - var t = lazy.Value; - } - catch (Exception ex) - { - e = ex; - } - Assert.NotNull(e); - Assert.Same(expected, e.GetType()); - } - - [Fact] - public static void CheckExceptions() - { - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); })); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, true)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, false)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); - - // These functions, possibly unintuitively, return a TargetInvocationException - CheckException(typeof(TargetInvocationException), new Lazy()); - CheckException(typeof(TargetInvocationException), new Lazy(true)); - CheckException(typeof(TargetInvocationException), new Lazy(false)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.None)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.PublicationOnly)); - - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99))); - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), true)); - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), false)); - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.None)); - CheckException(typeof(MyException), new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.PublicationOnly)); - } - - private static void SameException(Lazy x) - { - Exception first = null; - try - { - var _ = x.Value; - } - catch (Exception thrown1) - { - first = thrown1; - } - Assert.NotNull(first); - - try - { - var _ = x.Value; - } - catch (MyException thrown2) - { - Assert.Same(first, thrown2); - } - } - - private static void DifferentException(Lazy x) - { - Exception first = null; - try - { - var _ = x.Value; - } - catch (Exception thrown1) - { - first = thrown1; - } - Assert.NotNull(first); - - Exception second = null; - try - { - var _ = x.Value; - } - catch (Exception thrown2) - { - second = thrown2; - } - Assert.NotNull(second); - - Assert.NotEqual(first, second); - } - - [Fact] - public static void SameOrDifferentException() - { - SameException(new Lazy(() => { throw new MyException(99); })); - SameException(new Lazy(() => { throw new MyException(99); }, true)); - SameException(new Lazy(() => { throw new MyException(99); }, false)); - SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); - SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); - - DifferentException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); - - DifferentException(new Lazy()); - DifferentException(new Lazy(true)); - DifferentException(new Lazy(false)); - DifferentException(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); - DifferentException(new Lazy(LazyThreadSafetyMode.None)); - - DifferentException(new Lazy(LazyThreadSafetyMode.PublicationOnly)); - - SameException(new Lazy(() => new SimpleException(99))); - SameException(new Lazy(() => new SimpleException(99), true)); - SameException(new Lazy(() => new SimpleException(99), false)); - SameException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.ExecutionAndPublication)); - SameException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.None)); - - DifferentException(new Lazy(() => new SimpleException(99), LazyThreadSafetyMode.PublicationOnly)); - } - - private static void MultipleCallsToIntValue(Lazy lazy, ref int counter, int expected) - { - counter = 0; - var result = 0; - for (var i = 0; i < 10; ++i) - { - try { result = lazy.Value; } catch (Exception) { } - } - Assert.Equal(result, expected); - } - - private static void MultipleCallsToObjectValue(Lazy lazy, ref int counter, int? expected) - { - counter = 0; - var result = default(Simple); - for (var i = 0; i < 10; ++i) - { - try { result = lazy.Value; } catch (Exception) { } - } - if (expected == null) - Assert.Null(result); - else - Assert.Equal(result.Value, expected.Value); - } - - [Fact] - public static void MultipleValueCalls() - { - var counter = default(int); // set in test function - - var fint = new Func (() => { if (++counter < 5) throw new MyException(42); else return counter; }); - var fobj = new Func(() => { if (++counter < 5) throw new MyException(42); else return new Simple(counter); }); - - MultipleCallsToIntValue(new Lazy(fint), ref counter, 0); - MultipleCallsToIntValue(new Lazy(fint, true), ref counter, 0); - MultipleCallsToIntValue(new Lazy(fint, false), ref counter, 0); - MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, 0); - MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.None), ref counter, 0); - MultipleCallsToIntValue(new Lazy(fint, LazyThreadSafetyMode.PublicationOnly), ref counter, 5); - - MultipleCallsToObjectValue(new Lazy(fobj), ref counter, null); - MultipleCallsToObjectValue(new Lazy(fobj, true), ref counter, null); - MultipleCallsToObjectValue(new Lazy(fobj, false), ref counter, null); - MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.ExecutionAndPublication), ref counter, null); - MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.None), ref counter, null); - MultipleCallsToObjectValue(new Lazy(fobj, LazyThreadSafetyMode.PublicationOnly), ref counter, 5); - } - - class SimpleConstructor - { - public static int counter = 0; - public static int getValue() - { - if (++counter < 5) - throw new MyException(42); - else - return counter; - } - - public int Value { get; } - - public SimpleConstructor() - { - Value = getValue(); - } - } - - private static void MultipleCallsToConstructor(Lazy lazy, int? expected) - { - SimpleConstructor.counter = 0; - var result = default(SimpleConstructor); - for (var i = 0; i < 10; ++i) - { - try { result = lazy.Value; } catch (Exception) { } - } - if (expected == null) - Assert.Null(result); - else - Assert.Equal(result.Value, expected.Value); - } - - [Fact] - public static void MultipleCallsToExceptionThrowingConstructor() - { - MultipleCallsToConstructor(new Lazy(), 5); - MultipleCallsToConstructor(new Lazy(true), 5); - MultipleCallsToConstructor(new Lazy(false), 5); - MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication), 5); - MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.None), 5); - MultipleCallsToConstructor(new Lazy(LazyThreadSafetyMode.PublicationOnly), 5); - } - - private static void CheckForInvalidOperationException(ref Lazy x, Lazy lazy) - { - x = lazy; - - var correct = false; - try - { - var _ = lazy.Value; - } - catch (InvalidOperationException) - { - correct = true; - } - Assert.True(correct); - } - - [Fact] - public static void LazyRecursion() - { - Lazy x = null; - Func f = () => x.Value; - - CheckForInvalidOperationException(ref x, new Lazy(f)); - CheckForInvalidOperationException(ref x, new Lazy(f, true)); - CheckForInvalidOperationException(ref x, new Lazy(f, false)); - CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.ExecutionAndPublication)); - CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.None)); - - // this just stackoverflows in current and new implementation - // CheckForInvalidOperationException(ref x, new Lazy(f, LazyThreadSafetyMode.PublicationOnly)); - } - } -} From 0ea75c5f67a8a34d9ae36a5f5367f4a70752b7f0 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 7 Feb 2017 19:32:34 +1100 Subject: [PATCH 3/4] Modified to utilise TheoryAttribute --- src/System.Runtime/tests/System/LazyTests.cs | 230 ++++++++++--------- 1 file changed, 116 insertions(+), 114 deletions(-) diff --git a/src/System.Runtime/tests/System/LazyTests.cs b/src/System.Runtime/tests/System/LazyTests.cs index 92dd142a051f..0a33011c6732 100644 --- a/src/System.Runtime/tests/System/LazyTests.cs +++ b/src/System.Runtime/tests/System/LazyTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Threading; using System.Reflection; using System.IO; @@ -128,7 +129,7 @@ public static void Value_Invalid() // Value_Invalid_Impl(ref x, new Lazy(f, LazyThreadSafetyMode.PublicationOnly)); } - class InitiallyExceptionThrowingCtor + public class InitiallyExceptionThrowingCtor { public static int counter = 0; public static int getValue() @@ -147,7 +148,19 @@ public InitiallyExceptionThrowingCtor() } } - private static void Ctor_ExceptionRecovery_Impl(Lazy lazy, int? expected) + public static IEnumerable Ctor_ExceptionRecovery_MemberData() + { + yield return new object[] { new Lazy(), 5 }; + yield return new object[] { new Lazy(true), 5 }; + yield return new object[] { new Lazy(false), 5 }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.ExecutionAndPublication), 5 }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.None), 5 }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.PublicationOnly), 5 }; + } + + [Theory] + [MemberData(nameof(Ctor_ExceptionRecovery_MemberData))] + public static void Ctor_ExceptionRecovery(Lazy lazy, int? expected) { InitiallyExceptionThrowingCtor.counter = 0; var result = default(InitiallyExceptionThrowingCtor); @@ -161,17 +174,6 @@ private static void Ctor_ExceptionRecovery_Impl(Lazy(), 5); - Ctor_ExceptionRecovery_Impl(new Lazy(true), 5); - Ctor_ExceptionRecovery_Impl(new Lazy(false), 5); - Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication), 5); - Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.None), 5); - Ctor_ExceptionRecovery_Impl(new Lazy(LazyThreadSafetyMode.PublicationOnly), 5); - } - private static void Value_ExceptionRecovery_IntImpl(Lazy lazy, ref int counter, int expected) { counter = 0; @@ -241,126 +243,125 @@ public ExceptionInCtor(int value) } } - private static void CheckException(Type expected, Lazy lazy) + public static IEnumerable Value_Func_Exception_MemberData() { - Exception e = null; - try - { - var t = lazy.Value; - } - catch (Exception ex) - { - e = ex; - } - Assert.NotNull(e); - Assert.Same(expected, e.GetType()); + yield return new object[] { new Lazy(() => { throw new MyException(99); }) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, true) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, false) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly) }; } - [Fact] - public static void CheckExceptions() - { - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); })); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, true)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, false)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); - CheckException(typeof(MyException), new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); - - CheckException(typeof(TargetInvocationException), new Lazy()); - CheckException(typeof(TargetInvocationException), new Lazy(true)); - CheckException(typeof(TargetInvocationException), new Lazy(false)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.None)); - CheckException(typeof(TargetInvocationException), new Lazy(LazyThreadSafetyMode.PublicationOnly)); - - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99))); - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), true)); - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), false)); - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication)); - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None)); - CheckException(typeof(MyException), new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly)); - } - - private static void SameException(Lazy x) - { - Exception first = null; - try - { - var _ = x.Value; - } - catch (Exception thrown1) - { - first = thrown1; - } - Assert.NotNull(first); + [Theory] + [MemberData(nameof(Value_Func_Exception_MemberData))] + public static void Value_Func_Exception(Lazy lazy) + { + Assert.Throws(() => lazy.Value); + } - try - { - var _ = x.Value; - } - catch (MyException thrown2) - { - Assert.Same(first, thrown2); - } + public static IEnumerable Value_FuncCtor_Exception_MemberData() + { + yield return new object[] { new Lazy(() => new ExceptionInCtor(99)) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), true) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), false) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly) }; } - private static void DifferentException(Lazy x) + [Theory] + [MemberData(nameof(Value_FuncCtor_Exception_MemberData))] + public static void Value_FuncCtor_Exception(Lazy lazy) { - Exception first = null; - try - { - var _ = x.Value; - } - catch (Exception thrown1) - { - first = thrown1; - } - Assert.NotNull(first); + Assert.Throws(() => lazy.Value); + } - Exception second = null; - try - { - var _ = x.Value; - } - catch (Exception thrown2) - { - second = thrown2; - } - Assert.NotNull(second); + public static IEnumerable Value_TargetInvocationException_MemberData() + { + yield return new object[] { new Lazy() }; + yield return new object[] { new Lazy(true) }; + yield return new object[] { new Lazy(false) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.None) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.PublicationOnly) }; + } - Assert.NotEqual(first, second); + [Theory] + [MemberData(nameof(Value_TargetInvocationException_MemberData))] + public static void Value_TargetInvocationException(Lazy lazy) + { + Assert.Throws(() => lazy.Value); } - [Fact] - public static void SameOrDifferentException() + public static IEnumerable Exceptions_Func_Idempotent_MemberData() { - SameException(new Lazy(() => { throw new MyException(99); })); - SameException(new Lazy(() => { throw new MyException(99); }, true)); - SameException(new Lazy(() => { throw new MyException(99); }, false)); - SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication)); - SameException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None)); + yield return new object[] { new Lazy(() => { throw new MyException(99); }) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, true) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, false) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.None) }; + } - DifferentException(new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly)); + [Theory] + [MemberData(nameof(Exceptions_Func_Idempotent_MemberData))] + public static void Exceptions_Func_Idempotent(Lazy x) + { + var e = Assert.ThrowsAny(() => x.Value); + Assert.Same(e, Assert.ThrowsAny(() => x.Value)); + } - DifferentException(new Lazy()); - DifferentException(new Lazy(true)); - DifferentException(new Lazy(false)); - DifferentException(new Lazy(LazyThreadSafetyMode.ExecutionAndPublication)); - DifferentException(new Lazy(LazyThreadSafetyMode.None)); + public static IEnumerable Exceptions_Ctor_Idempotent_MemberData() + { + yield return new object[] { new Lazy(() => new ExceptionInCtor(99)) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), true) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), false) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None) }; + } - DifferentException(new Lazy(LazyThreadSafetyMode.PublicationOnly)); + [Theory] + [MemberData(nameof(Exceptions_Ctor_Idempotent_MemberData))] + public static void Exceptions_Ctor_Idempotent(Lazy x) + { + var e = Assert.ThrowsAny(() => x.Value); + Assert.Same(e, Assert.ThrowsAny(() => x.Value)); + } + + public static IEnumerable Exceptions_Func_NotIdempotent_MemberData() + { + yield return new object[] { new Lazy(() => { throw new MyException(99); }, LazyThreadSafetyMode.PublicationOnly) }; + } + + public static IEnumerable Exceptions_Ctor_NotIdempotent_MemberData() + { + yield return new object[] { new Lazy() }; + yield return new object[] { new Lazy(true) }; + yield return new object[] { new Lazy(false) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.ExecutionAndPublication) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.None) }; + yield return new object[] { new Lazy(LazyThreadSafetyMode.PublicationOnly) }; + yield return new object[] { new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly) }; + } - SameException(new Lazy(() => new ExceptionInCtor(99))); - SameException(new Lazy(() => new ExceptionInCtor(99), true)); - SameException(new Lazy(() => new ExceptionInCtor(99), false)); - SameException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.ExecutionAndPublication)); - SameException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.None)); + [Theory] + [MemberData(nameof(Exceptions_Func_NotIdempotent_MemberData))] + public static void Exceptions_Func_NotIdempotent(Lazy x) + { + var e = Assert.ThrowsAny(() => x.Value); + Assert.NotSame(e, Assert.ThrowsAny(() => x.Value)); + } - DifferentException(new Lazy(() => new ExceptionInCtor(99), LazyThreadSafetyMode.PublicationOnly)); + [Theory] + [MemberData(nameof(Exceptions_Ctor_NotIdempotent_MemberData))] + public static void Exceptions_Ctor_NotIdempotent(Lazy x) + { + var e = Assert.ThrowsAny(() => x.Value); + Assert.NotSame(e, Assert.ThrowsAny(() => x.Value)); } [Fact] - static void Serialization_ValueType() + public static void Serialization_ValueType() { var stream = new MemoryStream(); var formatter = new BinaryFormatter(); @@ -373,13 +374,14 @@ static void Serialization_ValueType() } [Fact] - static void Serialization_RefType() + public static void Serialization_RefType() { var stream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize(stream, new Lazy(() => "42")); stream.Seek(0, SeekOrigin.Begin); + var x = BinaryFormatterHelpers.Clone(new object()); var fortytwo = (Lazy)formatter.Deserialize(stream); Assert.True(fortytwo.IsValueCreated); Assert.Equal(fortytwo.Value, "42"); From 77bfcd7fb5670667b22d29b778abc6a0c34e43cc Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 19 Feb 2017 13:46:08 +1100 Subject: [PATCH 4/4] Minor clean up as per review --- src/System.Runtime/tests/System/LazyTests.cs | 21 ++++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/System.Runtime/tests/System/LazyTests.cs b/src/System.Runtime/tests/System/LazyTests.cs index 0a33011c6732..6badc2072456 100644 --- a/src/System.Runtime/tests/System/LazyTests.cs +++ b/src/System.Runtime/tests/System/LazyTests.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.IO; using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization.Formatters.Tests; using Xunit; namespace System.Tests @@ -110,7 +111,7 @@ public static void ToString_DoesntForceAllocation() private static void Value_Invalid_Impl(ref Lazy x, Lazy lazy) { x = lazy; - Assert.Throws(() => { var dummy = lazy.Value; }); + Assert.Throws(() => lazy.Value); } [Fact] @@ -160,24 +161,21 @@ public static IEnumerable Ctor_ExceptionRecovery_MemberData() [Theory] [MemberData(nameof(Ctor_ExceptionRecovery_MemberData))] - public static void Ctor_ExceptionRecovery(Lazy lazy, int? expected) + public static void Ctor_ExceptionRecovery(Lazy lazy, int expected) { InitiallyExceptionThrowingCtor.counter = 0; - var result = default(InitiallyExceptionThrowingCtor); + InitiallyExceptionThrowingCtor result = null; for (var i = 0; i < 10; ++i) { try { result = lazy.Value; } catch (Exception) { } } - if (expected == null) - Assert.Null(result); - else - Assert.Equal(result.Value, expected.Value); + Assert.Equal(result.Value, expected); } private static void Value_ExceptionRecovery_IntImpl(Lazy lazy, ref int counter, int expected) { counter = 0; - var result = 0; + int result = 0; for (var i = 0; i < 10; ++i) { try { result = lazy.Value; } catch (Exception) { } @@ -193,16 +191,13 @@ private static void Value_ExceptionRecovery_StringImpl(Lazy lazy, ref in { try { result = lazy.Value; } catch (Exception) { } } - if (expected == null) - Assert.Null(result); - else - Assert.Equal(result, expected); + Assert.Equal(expected, result); } [Fact] public static void Value_ExceptionRecovery() { - var counter = default(int); // set in test function + int counter = 0; // set in test function var fint = new Func (() => { if (++counter < 5) throw new Exception(); else return counter; }); var fobj = new Func(() => { if (++counter < 5) throw new Exception(); else return counter.ToString(); });