浏览代码

Moving [First|Last|Single][OrDefault] tests.

Bart De Smet 8 年之前
父节点
当前提交
4d99075a0c

+ 0 - 511
Ix.NET/Source/System.Interactive.Async.Tests/AsyncTests.Aggregates.cs

@@ -26,517 +26,6 @@ namespace Tests
             await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerableEx.IsEmpty<int>(null, CancellationToken.None));
         }
 
-        [Fact]
-        public async Task First_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void First1()
-        {
-            var res = AsyncEnumerable.Empty<int>().First();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void First2()
-        {
-            var res = AsyncEnumerable.Empty<int>().First(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void First3()
-        {
-            var res = AsyncEnumerable.Return(42).First(x => x % 2 != 0);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void First4()
-        {
-            var res = AsyncEnumerable.Return(42).First();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void First5()
-        {
-            var res = AsyncEnumerable.Return(42).First(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void First6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).First();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void First7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).First(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void First8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().First();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void First9()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().First(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public async Task FirstOrDefault_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void FirstOrDefault1()
-        {
-            var res = AsyncEnumerable.Empty<int>().FirstOrDefault();
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault2()
-        {
-            var res = AsyncEnumerable.Empty<int>().FirstOrDefault(x => true);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault3()
-        {
-            var res = AsyncEnumerable.Return(42).FirstOrDefault(x => x % 2 != 0);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault4()
-        {
-            var res = AsyncEnumerable.Return(42).FirstOrDefault();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault5()
-        {
-            var res = AsyncEnumerable.Return(42).FirstOrDefault(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).FirstOrDefault();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void FirstOrDefault7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).FirstOrDefault(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void FirstOrDefault8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault9()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public void FirstOrDefault10()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault(x => x < 10);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public async Task Last_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void Last1()
-        {
-            var res = AsyncEnumerable.Empty<int>().Last();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Last2()
-        {
-            var res = AsyncEnumerable.Empty<int>().Last(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Last3()
-        {
-            var res = AsyncEnumerable.Return(42).Last(x => x % 2 != 0);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Last4()
-        {
-            var res = AsyncEnumerable.Return(42).Last();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void Last5()
-        {
-            var res = AsyncEnumerable.Return(42).Last(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void Last6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).Last();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void Last7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).Last(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void Last8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Last();
-            Assert.Equal(90, res.Result);
-        }
-
-        [Fact]
-        public void Last9()
-        {
-            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().Last(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public async Task LastOrDefault_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void LastOrDefault1()
-        {
-            var res = AsyncEnumerable.Empty<int>().LastOrDefault();
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault2()
-        {
-            var res = AsyncEnumerable.Empty<int>().LastOrDefault(x => true);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault3()
-        {
-            var res = AsyncEnumerable.Return(42).LastOrDefault(x => x % 2 != 0);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault4()
-        {
-            var res = AsyncEnumerable.Return(42).LastOrDefault();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault5()
-        {
-            var res = AsyncEnumerable.Return(42).LastOrDefault(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).LastOrDefault();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void LastOrDefault7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).LastOrDefault(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void LastOrDefault8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().LastOrDefault();
-            Assert.Equal(90, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault9()
-        {
-            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().LastOrDefault(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public void LastOrDefault10()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().LastOrDefault(x => x < 10);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public async Task Single_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void Single1()
-        {
-            var res = AsyncEnumerable.Empty<int>().Single();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Single2()
-        {
-            var res = AsyncEnumerable.Empty<int>().Single(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Single3()
-        {
-            var res = AsyncEnumerable.Return(42).Single(x => x % 2 != 0);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Single4()
-        {
-            var res = AsyncEnumerable.Return(42).Single();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void Single5()
-        {
-            var res = AsyncEnumerable.Return(42).Single(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void Single6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).Single();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void Single7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).Single(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void Single8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Single();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Single9()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Single(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public void Single10()
-        {
-            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().Single(x => x % 2 != 0);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void Single11()
-        {
-            var res = new int[0].ToAsyncEnumerable().Single();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public async Task SingleOrDefault_Null()
-        {
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, x => true));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
-
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, x => true, CancellationToken.None));
-            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
-        }
-
-        [Fact]
-        public void SingleOrDefault1()
-        {
-            var res = AsyncEnumerable.Empty<int>().SingleOrDefault();
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault2()
-        {
-            var res = AsyncEnumerable.Empty<int>().SingleOrDefault(x => true);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault3()
-        {
-            var res = AsyncEnumerable.Return(42).SingleOrDefault(x => x % 2 != 0);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault4()
-        {
-            var res = AsyncEnumerable.Return(42).SingleOrDefault();
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault5()
-        {
-            var res = AsyncEnumerable.Return(42).SingleOrDefault(x => x % 2 == 0);
-            Assert.Equal(42, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault6()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).SingleOrDefault();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void SingleOrDefault7()
-        {
-            var ex = new Exception("Bang!");
-            var res = AsyncEnumerable.Throw<int>(ex).SingleOrDefault(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
-        }
-
-        [Fact]
-        public void SingleOrDefault8()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault();
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void SingleOrDefault9()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => x % 2 != 0);
-            Assert.Equal(45, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault10()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => x < 10);
-            Assert.Equal(0, res.Result);
-        }
-
-        [Fact]
-        public void SingleOrDefault11()
-        {
-            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => true);
-            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
-        }
-
-        [Fact]
-        public void SingleOrDefault12()
-        {
-            var res = new int[0].ToAsyncEnumerable().SingleOrDefault();
-            Assert.Equal(0, res.Result);
-        }
-
         [Fact]
         public async Task ElementAt_Null()
         {

+ 92 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/First.cs

@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class First : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task First_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.First<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void First1()
+        {
+            var res = AsyncEnumerable.Empty<int>().First();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void First2()
+        {
+            var res = AsyncEnumerable.Empty<int>().First(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void First3()
+        {
+            var res = AsyncEnumerable.Return(42).First(x => x % 2 != 0);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void First4()
+        {
+            var res = AsyncEnumerable.Return(42).First();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void First5()
+        {
+            var res = AsyncEnumerable.Return(42).First(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void First6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).First();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void First7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).First(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void First8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().First();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void First9()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().First(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+    }
+}

+ 99 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/FirstOrDefault.cs

@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class FirstOrDefault : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task FirstOrDefault_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.FirstOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void FirstOrDefault1()
+        {
+            var res = AsyncEnumerable.Empty<int>().FirstOrDefault();
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault2()
+        {
+            var res = AsyncEnumerable.Empty<int>().FirstOrDefault(x => true);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault3()
+        {
+            var res = AsyncEnumerable.Return(42).FirstOrDefault(x => x % 2 != 0);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault4()
+        {
+            var res = AsyncEnumerable.Return(42).FirstOrDefault();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault5()
+        {
+            var res = AsyncEnumerable.Return(42).FirstOrDefault(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).FirstOrDefault();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void FirstOrDefault7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).FirstOrDefault(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void FirstOrDefault8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault9()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+
+        [Fact]
+        public void FirstOrDefault10()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().FirstOrDefault(x => x < 10);
+            Assert.Equal(0, res.Result);
+        }
+    }
+}

+ 92 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/Last.cs

@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class Last : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task Last_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Last<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void Last1()
+        {
+            var res = AsyncEnumerable.Empty<int>().Last();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Last2()
+        {
+            var res = AsyncEnumerable.Empty<int>().Last(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Last3()
+        {
+            var res = AsyncEnumerable.Return(42).Last(x => x % 2 != 0);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Last4()
+        {
+            var res = AsyncEnumerable.Return(42).Last();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void Last5()
+        {
+            var res = AsyncEnumerable.Return(42).Last(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void Last6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).Last();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void Last7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).Last(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void Last8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Last();
+            Assert.Equal(90, res.Result);
+        }
+
+        [Fact]
+        public void Last9()
+        {
+            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().Last(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+    }
+}

+ 99 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/LastOrDefault.cs

@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class LastOrDefault : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task LastOrDefault_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.LastOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void LastOrDefault1()
+        {
+            var res = AsyncEnumerable.Empty<int>().LastOrDefault();
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault2()
+        {
+            var res = AsyncEnumerable.Empty<int>().LastOrDefault(x => true);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault3()
+        {
+            var res = AsyncEnumerable.Return(42).LastOrDefault(x => x % 2 != 0);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault4()
+        {
+            var res = AsyncEnumerable.Return(42).LastOrDefault();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault5()
+        {
+            var res = AsyncEnumerable.Return(42).LastOrDefault(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).LastOrDefault();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void LastOrDefault7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).LastOrDefault(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void LastOrDefault8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().LastOrDefault();
+            Assert.Equal(90, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault9()
+        {
+            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().LastOrDefault(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+
+        [Fact]
+        public void LastOrDefault10()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().LastOrDefault(x => x < 10);
+            Assert.Equal(0, res.Result);
+        }
+    }
+}

+ 106 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/Single.cs

@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class Single : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task Single_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.Single<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void Single1()
+        {
+            var res = AsyncEnumerable.Empty<int>().Single();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Single2()
+        {
+            var res = AsyncEnumerable.Empty<int>().Single(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Single3()
+        {
+            var res = AsyncEnumerable.Return(42).Single(x => x % 2 != 0);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Single4()
+        {
+            var res = AsyncEnumerable.Return(42).Single();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void Single5()
+        {
+            var res = AsyncEnumerable.Return(42).Single(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void Single6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).Single();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void Single7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).Single(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void Single8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Single();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Single9()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().Single(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+
+        [Fact]
+        public void Single10()
+        {
+            var res = new[] { 42, 23, 45, 90 }.ToAsyncEnumerable().Single(x => x % 2 != 0);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void Single11()
+        {
+            var res = new int[0].ToAsyncEnumerable().Single();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+    }
+}

+ 113 - 0
Ix.NET/Source/System.Linq.Async.Tests/System/Linq/Operators/SingleOrDefault.cs

@@ -0,0 +1,113 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information. 
+
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Tests
+{
+    public class SingleOrDefault : AsyncEnumerableTests
+    {
+        [Fact]
+        public async Task SingleOrDefault_Null()
+        {
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, x => true));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>)));
+
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(null, x => true, CancellationToken.None));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => AsyncEnumerable.SingleOrDefault<int>(AsyncEnumerable.Return(42), default(Func<int, bool>), CancellationToken.None));
+        }
+
+        [Fact]
+        public void SingleOrDefault1()
+        {
+            var res = AsyncEnumerable.Empty<int>().SingleOrDefault();
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault2()
+        {
+            var res = AsyncEnumerable.Empty<int>().SingleOrDefault(x => true);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault3()
+        {
+            var res = AsyncEnumerable.Return(42).SingleOrDefault(x => x % 2 != 0);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault4()
+        {
+            var res = AsyncEnumerable.Return(42).SingleOrDefault();
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault5()
+        {
+            var res = AsyncEnumerable.Return(42).SingleOrDefault(x => x % 2 == 0);
+            Assert.Equal(42, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault6()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).SingleOrDefault();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void SingleOrDefault7()
+        {
+            var ex = new Exception("Bang!");
+            var res = AsyncEnumerable.Throw<int>(ex).SingleOrDefault(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() == ex);
+        }
+
+        [Fact]
+        public void SingleOrDefault8()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault();
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void SingleOrDefault9()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => x % 2 != 0);
+            Assert.Equal(45, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault10()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => x < 10);
+            Assert.Equal(0, res.Result);
+        }
+
+        [Fact]
+        public void SingleOrDefault11()
+        {
+            var res = new[] { 42, 45, 90 }.ToAsyncEnumerable().SingleOrDefault(x => true);
+            AssertThrows<Exception>(() => res.Wait(WaitTimeoutMs), ex_ => ((AggregateException)ex_).Flatten().InnerExceptions.Single() is InvalidOperationException);
+        }
+
+        [Fact]
+        public void SingleOrDefault12()
+        {
+            var res = new int[0].ToAsyncEnumerable().SingleOrDefault();
+            Assert.Equal(0, res.Result);
+        }
+    }
+}