Merge pull request #1896 from meum/patch-1
[mono.git] / mcs / class / corlib / Test / System / LazyTest.cs
index 15852c4575d59e8abf85c9df6a69111d93c266e9..0b3e042e3097b6021ea395e5e2c7987f5c07f222 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_4_0
-
 using System;
 using System.Reflection;
-using System.Reflection.Emit;
 using System.Threading;
 using NUnit.Framework;
 
@@ -48,10 +45,11 @@ namespace MonoTests.System
                        new Lazy<int> (null);
                }
 
+
                [Test]
                [ExpectedException (typeof (ArgumentNullException))]
                public void Ctor_Null_2 () {
-                       new Lazy<int> (null, LazyExecutionMode.NotThreadSafe);
+                       new Lazy<int> (null, false);
                }
 
                [Test]
@@ -84,11 +82,14 @@ namespace MonoTests.System
                }
 
                [Test]
-               [ExpectedException (typeof (MissingMemberException))]
                public void NoDefaultCtor () {
                        var l1 = new Lazy<NoDefaultCtorClass> ();
                        
-                       var o = l1.Value;
+                       try {
+                               var o = l1.Value;
+                               Assert.Fail ();
+                       } catch (MissingMemberException) {
+                       }
                }
 
                class NoDefaultCtorClass {
@@ -110,30 +111,216 @@ namespace MonoTests.System
                static int counter;
 
                [Test]
-               public void EnsureSingleThreadSafeExecution () {
+               public void EnsureSingleThreadSafeExecution ()
+               {
                        counter = 42;
+                       bool started = false;
 
-                       //var l = new Lazy<int> (delegate () { return counter ++; }, LazyExecutionMode.NotThreadSafe);
-                       var l = new Lazy<int> (delegate () { return counter ++; }, LazyExecutionMode.EnsureSingleThreadSafeExecution);
-
+                       var l = new Lazy<int> (delegate () { return counter ++; }, true);
+                       bool failed = false;
                        object monitor = new object ();
-                       var threads = new Thread [10];
-                       for (int i = 0; i < 10; ++i) {
+                       var threads = new Thread [4];
+                       for (int i = 0; i < threads.Length; ++i) {
                                threads [i] = new Thread (delegate () {
                                                lock (monitor) {
-                                                       Monitor.Wait (monitor);
+                                                       if (!started) {
+                                                               if (!Monitor.Wait (monitor, 2000))
+                                                                       failed = true;
+                                                       }
                                                }
                                                int val = l.Value;
                                        });
                        }
-                       for (int i = 0; i < 10; ++i)
+                       for (int i = 0; i < threads.Length; ++i)
                                threads [i].Start ();
-                       lock (monitor)
+                       lock (monitor) {
+                               started = true;
                                Monitor.PulseAll (monitor);
-                       
+                       }
+
+                       for (int i = 0; i < threads.Length; ++i)
+                               threads [i].Join ();
+
+                       Assert.IsFalse (failed);
                        Assert.AreEqual (42, l.Value);
-               }                       
+               }
+               
+               [Test]
+               public void InitRecursion ()
+               {
+                       Lazy<DefaultCtorClass> c = null;
+                       c = new Lazy<DefaultCtorClass> (() => { Console.WriteLine (c.Value); return null; });
+                       
+                       try {
+                               var r = c.Value;
+                               Assert.Fail ();
+                       } catch (InvalidOperationException) {
+                       }
+               }
+
+               [Test]
+               public void ModeNone ()
+               {
+                       int x;
+                       bool fail = true;
+                       Lazy<int> lz = new Lazy<int> (() => { if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.None);
+                       try {
+                               x = lz.Value;
+                               Assert.Fail ("#1");
+                               Console.WriteLine (x);
+                       } catch (Exception ex) { }
+
+                       try {
+                               x = lz.Value;
+                               Assert.Fail ("#2");
+                       } catch (Exception ex) { }
+
+                       fail = false;
+                       try {
+                               x = lz.Value;
+                               Assert.Fail ("#3");
+                       } catch (Exception ex) { }
+
+                       bool rec = true;
+                       lz = new Lazy<int> (() => rec ? lz.Value : 99, LazyThreadSafetyMode.None);
+
+                       try {
+                               x = lz.Value;
+                               Assert.Fail ("#4");
+                       } catch (InvalidOperationException ex) { }
+
+                       rec = false;
+                       try {
+                               x = lz.Value;
+                               Assert.Fail ("#5");
+                       } catch (InvalidOperationException ex) { }
+               }
+
+               [Test]
+               public void ModePublicationOnly () {
+                       bool fail = true;
+                       int invoke = 0;
+                       Lazy<int> lz = new Lazy<int> (() => { ++invoke; if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.PublicationOnly);
+
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#1");
+                               Console.WriteLine (x);
+                       } catch (Exception ex) { }
+
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#2");
+                       } catch (Exception ex) { }
+
+
+                       Assert.AreEqual (2, invoke, "#3");
+                       fail = false;
+                       Assert.AreEqual (99,  lz.Value, "#4");
+                       Assert.AreEqual (3, invoke, "#5");
+
+                       invoke = 0;
+                       bool rec = true;
+                       lz = new Lazy<int> (() => { ++invoke; bool r = rec; rec = false; return r ? lz.Value : 88; },   LazyThreadSafetyMode.PublicationOnly);
+
+                       Assert.AreEqual (88,  lz.Value, "#6");
+                       Assert.AreEqual (2, invoke, "#7");
+               }
+
+               [Test]
+               public void ModeExecutionAndPublication () {
+                       int invoke = 0;
+                       bool fail = true;
+                       Lazy<int> lz = new Lazy<int> (() => { ++invoke; if (fail) throw new Exception (); else return 99; }, LazyThreadSafetyMode.ExecutionAndPublication);
+
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#1");
+                               Console.WriteLine (x);
+                       } catch (Exception ex) { }
+                       Assert.AreEqual (1, invoke, "#2");
+
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#3");
+                       } catch (Exception ex) { }
+                       Assert.AreEqual (1, invoke, "#4");
+
+                       fail = false;
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#5");
+                       } catch (Exception ex) { }
+                       Assert.AreEqual (1, invoke, "#6");
+
+                       bool rec = true;
+                       lz = new Lazy<int> (() => rec ? lz.Value : 99, LazyThreadSafetyMode.ExecutionAndPublication);
+
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#7");
+                       } catch (InvalidOperationException ex) { }
+
+                       rec = false;
+                       try {
+                               int x = lz.Value;
+                               Assert.Fail ("#8");
+                       } catch (InvalidOperationException ex) { }
+               }
+
+               static int Return22 () {
+                       return 22;
+               }
+
+               [Test]
+               public void Trivial_Lazy () {
+                       var x = new Lazy<int> (Return22, false);
+                       Assert.AreEqual (22, x.Value, "#1");
+               }
+
+               [Test]
+               public void ConcurrentInitialization ()
+               {
+                       var init = new AutoResetEvent (false);
+                       var e1_set = new AutoResetEvent (false);
+
+                       var lazy = new Lazy<string> (() => {
+                               init.Set ();
+                               Thread.Sleep (10);
+                               throw new ApplicationException ();
+                       });
+
+                       Exception e1 = null;
+                       var thread = new Thread (() => {
+                               try {
+                                       string value = lazy.Value;
+                               } catch (Exception ex) {
+                                       e1 = ex;
+                                       e1_set.Set ();
+                               }
+                       });
+                       thread.Start ();
+
+                       Assert.IsTrue (init.WaitOne (3000), "#1");
+
+                       Exception e2 = null;
+                       try {
+                               string value = lazy.Value;
+                       } catch (Exception ex) {
+                               e2 = ex;
+                       }
+
+                       Exception e3 = null;
+                       try {
+                               string value = lazy.Value;
+                       } catch (Exception ex) {
+                               e3 = ex;
+                       }
+
+                       Assert.IsTrue (e1_set.WaitOne (3000), "#2");
+                       Assert.AreSame (e1, e2, "#3");
+                       Assert.AreSame (e1, e3, "#4");
+               }
+
        }
 }
-
-#endif