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