﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by AsyncGenerator.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using NHibernate.Driver;
using NHibernate.Linq;
using NHibernate.SqlTypes;
using NHibernate.Util;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH3850
{
	using System.Threading.Tasks;
	using System.Threading;
	[TestFixture]
	public class FixtureAsync : BugTestCase
	{
		private const string _searchName1 = "name";
		private const string _searchName2 = "name2";
		private const int _totalEntityCount = 10;
		private readonly DateTime _testDate = DateTime.Now;
		private readonly DateTimeOffset _testDateWithOffset = DateTimeOffset.Now;

		protected override bool AppliesTo(Dialect.Dialect dialect)
		{
			return TestDialect.SupportsSqlType(new SqlType(DbType.DateTimeOffset));
		}

		protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory)
		{
			// Cannot handle DbType.DateTimeOffset via ODBC.
			return !(factory.ConnectionProvider.Driver is OdbcDriver);
		}

		protected override void OnSetUp()
		{
			base.OnSetUp();
			using (var session = OpenSession())
			{
				var dateTime1 = _testDate.AddDays(-1);
				var dateTime2 = _testDate.AddDays(1);
				var dateTimeOffset1 = _testDateWithOffset.AddDays(-1);
				var dateTimeOffset2 = _testDateWithOffset.AddDays(1);
				Action<DomainClassBase> init1 = dc =>
				{
					dc.Id = 1;
					dc.Name = _searchName1;
					dc.Integer = 1;
					dc.Long = 1;
					dc.Decimal = 1;
					dc.Double = 1;
					dc.DateTime = dateTime1;
					dc.DateTimeOffset = dateTimeOffset1;
					dc.NonNullableDecimal = 1;
				};
				Action<DomainClassBase> init2 = dc =>
				{
					dc.Id = 2;
					dc.Name = _searchName2;
					dc.Integer = 2;
					dc.Long = 2;
					dc.Decimal = 2;
					dc.Double = 2;
					dc.DateTime = dateTime2;
					dc.DateTimeOffset = dateTimeOffset2;
					dc.NonNullableDecimal = 2;
				};

				DomainClassBase entity = new DomainClassBExtendedByA();
				init1(entity);
				session.Save(entity);
				entity = new DomainClassBExtendedByA();
				init2(entity);
				session.Save(entity);

				entity = new DomainClassCExtendedByD();
				init1(entity);
				session.Save(entity);
				entity = new DomainClassCExtendedByD();
				init2(entity);
				session.Save(entity);

				entity = new DomainClassE();
				init1(entity);
				session.Save(entity);
				entity = new DomainClassE();
				init2(entity);
				session.Save(entity);

				entity = new DomainClassGExtendedByH();
				init1(entity);
				session.Save(entity);
				entity = new DomainClassGExtendedByH();
				init2(entity);
				session.Save(entity);
				entity = new DomainClassHExtendingG
				{
					Id = 3,
					Name = _searchName1,
					Integer = 3,
					Long = 3,
					Decimal = 3,
					Double = 3,
					DateTime = dateTime1,
					DateTimeOffset = dateTimeOffset1,
					NonNullableDecimal = 3
				};
				session.Save(entity);
				entity = new DomainClassHExtendingG
				{
					Id = 4,
					Name = _searchName2,
					Integer = 4,
					Long = 4,
					Decimal = 4,
					Double = 4,
					DateTime = dateTime2,
					DateTimeOffset = dateTimeOffset2,
					NonNullableDecimal = 4
				};
				session.Save(entity);

				session.Flush();
			}
		}

		protected override void OnTearDown()
		{
			base.OnTearDown();
			using (var session = OpenSession())
			{
				var hql = "from System.Object";
				session.Delete(hql);
				session.Flush();
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AggregateGBaseAsync()
		{
			using (var session = OpenSession())
			{
				// This case should work because the aggregate is insensitive to ordering.
				var query = session.Query<DomainClassGExtendedByH>()
				                   .OrderBy(dc => dc.Id)
				                   .Select(dc => dc.Id);
				var result = query.Aggregate((p, n) => p + n);
				Assert.That(result, Is.EqualTo(10));
				var futureQuery = query.ToFutureValue(qdc => qdc.Aggregate((p, n) => p + n));
				Assert.That(await (futureQuery.GetValueAsync()), Is.EqualTo(10), "Future");
			}
		}

		// Failing case due to lack of polymorphic results ordering.
		[Test, Ignore("Polymorphic results sets are unioned without reordering, whatever the API")]
		public async Task AggregateGBaseOrderingMismatchAsync()
		{
			using (var session = OpenSession())
			{
				// This case cannot work because the aggregate is sensitive to ordering, and NHibernate currently always order polymorphic queries by class names,
				// then only honors query ordering as secondary order criteria.
				var query = session.Query<DomainClassGExtendedByH>()
				                   .OrderByDescending(dc => dc.Id)
				                   .Select(dc => dc.Id.ToString());
				var result = query.Aggregate((p, n) => p + "," + n);
				// Currently yields "2,1,4,3" instead.
				Assert.That(result, Is.EqualTo("4,3,2,1"));
				var futureQuery = query.ToFutureValue(qdc => qdc.Aggregate((p, n) => p + "," + n));
				Assert.That(await (futureQuery.GetValueAsync()), Is.EqualTo("4,3,2,1"), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AggregateMutableSeedGBaseAsync()
		{
			using (var session = OpenSession())
			{
				// This case works because the ordering accidentally matches with classes ordering.
				// (And moreover, with current dataset, selected values are same whatever the classes.)
				var query = session.Query<DomainClassGExtendedByH>()
				                    .OrderBy(dc => dc.Id);
				var seed = new StringBuilder();
				var result = query.Aggregate(seed, (s, dc) => s.Append(dc.Name).Append(","));
				var expectedResult = _searchName1 + "," + _searchName2 + "," + _searchName1 + "," + _searchName2 + ",";
				Assert.That(result.ToString(), Is.EqualTo(expectedResult));
				// We are dodging another bug here: the seed is cached in query plan... So giving another seed to Future
				// keeps re-using the seed used for non future above.
				seed.Clear();
				var futureQuery = query.ToFutureValue(qdc => qdc.Aggregate(seed, (s, dc) => s.Append(dc.Name).Append(",")));
				Assert.That((await (futureQuery.GetValueAsync())).ToString(), Is.EqualTo(expectedResult), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AggregateSeedGBaseAsync()
		{
			using (var session = OpenSession())
			{
				// This case should work because the aggregate is insensitive to ordering.
				var query = session.Query<DomainClassGExtendedByH>()
				                   .OrderBy(dc => dc.Id);
				var result = query.Aggregate(5, (s, dc) => s + dc.Id);
				Assert.That(result, Is.EqualTo(15));
				var futureQuery = query.ToFutureValue(qdc => qdc.Aggregate(5, (s, dc) => s + dc.Id));
				Assert.That(await (futureQuery.GetValueAsync()), Is.EqualTo(15), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AllBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AllCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AllEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AllFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AllGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AllGBaseWithNameFilteredByNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassGExtendedByH>()
				                   .Where(dc => dc.Name == _searchName1);
				var result = await (query.AllAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				var futureQuery = query.ToFutureValue(qdc => qdc.All(dc => dc.Name == _searchName1));
				Assert.That(await (futureQuery.GetValueAsync()), Is.True, "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AnyBBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().AnyAsync());
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AnyBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().AnyAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.Any(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyCBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().AnyAsync());
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().AnyAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.Any(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyEAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().AnyAsync());
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().AnyAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.Any(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyFAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().AnyAsync());
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().AnyAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.False);
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.Any(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.False, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyGBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().AnyAsync());
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task AnyGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().AnyAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.True);
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.Any(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task AnyObjectAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<object>().AnyAsync());
				Assert.That(result, Is.True);
				result = await (session.Query<object>().ToFutureValue(qdc => qdc.Any()).GetValueAsync());
				Assert.That(result, Is.True, "Future");
			}
		}

		[Test, Ignore("Won't fix: requires reshaping the query")]
		public Task AverageBBaseAsync()
		{
			return AverageAsync<DomainClassBExtendedByA>(1.5m);
		}

		[Test, Ignore("Won't fix: requires reshaping the query")]
		public Task AverageCBaseAsync()
		{
			return AverageAsync<DomainClassCExtendedByD>(1.5m);
		}

		// Non-reg case
		[Test]
		public Task AverageEAsync()
		{
			return AverageAsync<DomainClassE>(1.5m);
		}

		// Non-reg case
		[Test]
		public Task AverageFAsync()
		{
			return AverageAsync<DomainClassF>(null);
		}

		[Test, Ignore("Won't fix: requires reshaping the query")]
		public Task AverageGBaseAsync()
		{
			return AverageAsync<DomainClassGExtendedByH>(2.5m);
		}

		private async Task AverageAsync<DC>(decimal? expectedResult, CancellationToken cancellationToken = default(CancellationToken)) where DC : DomainClassBase
		{
			using (var session = OpenSession())
			{
				var dcQuery = session.Query<DC>();
				var integ = await (dcQuery.AverageAsync(dc => dc.Integer, cancellationToken));
				Assert.AreEqual(expectedResult, integ, "Integer average has failed");
				var futureInteg = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.Integer));
				Assert.That(await (futureInteg.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future integer average has failed");

				var longInt = await (dcQuery.AverageAsync(dc => dc.Long, cancellationToken));
				Assert.AreEqual(expectedResult, longInt, "Long integer average has failed");
				var futureLongInt = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.Long));
				Assert.That(await (futureLongInt.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future long integer average has failed");

				var dec = await (dcQuery.AverageAsync(dc => dc.Decimal, cancellationToken));
				Assert.AreEqual(expectedResult, dec, "Decimal average has failed");
				var futureDec = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.Decimal));
				Assert.That(await (futureDec.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future decimal average has failed");

				var dbl = await (dcQuery.AverageAsync(dc => dc.Double, cancellationToken));
				Assert.That(dbl.HasValue, Is.EqualTo(expectedResult.HasValue),"Double average has failed");
				if (expectedResult.HasValue)
					Assert.That(dbl.Value, Is.EqualTo(expectedResult).Within(0.001d), "Double average has failed");
				var futureDbl = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.Double));
				Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).HasValue, Is.EqualTo(expectedResult.HasValue),"Future double average has failed");
				if (expectedResult.HasValue)
					Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).Value, Is.EqualTo(expectedResult).Within(0.001d), "Future double average has failed");

				if (expectedResult.HasValue)
				{
					var nonNullableDecimal = -1m;
					Assert.That(async () => nonNullableDecimal = await (dcQuery.AverageAsync(dc => dc.NonNullableDecimal, cancellationToken)), Throws.Nothing, "Non nullable decimal average has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Non nullable decimal average has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.NonNullableDecimal));
					Assert.That(async () => nonNullableDecimal = await (futureNonNullableDec.GetValueAsync(cancellationToken)), Throws.Nothing, "Future non nullable decimal average has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Future non nullable decimal average has failed");
				}
				else
				{
					Assert.That(() => dcQuery.AverageAsync(dc => dc.NonNullableDecimal, cancellationToken),
					            // After fix
					            Throws.InstanceOf<InvalidOperationException>()
					                  // Before fix
					                  .Or.InnerException.InstanceOf<ArgumentNullException>(),
					            "Non nullable decimal average has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Average(dc => dc.NonNullableDecimal));
					Assert.That(() => futureNonNullableDec.GetValueAsync(cancellationToken),
					            Throws.InstanceOf<ArgumentNullException>(),
					            "Future non nullable decimal average has failed");
				}
			}
		}

		[Test, Ignore("Won't fix: requires reshaping the query")]
		public async Task AverageObjectAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<object>().AverageAsync(o => (int?)2));
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<object>().ToFutureValue(qdc => qdc.Average(o => (int?)2)).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task CountBBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().CountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task CountBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().CountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.Count(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountCBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().CountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().CountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.Count(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountEAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().CountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().CountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.Count(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountFAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().CountAsync());
				Assert.That(result, Is.EqualTo(0));
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(0), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task CountFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().CountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(0));
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.Count(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(0), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task CountGBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().CountAsync());
				Assert.That(result, Is.EqualTo(4));
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(4), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task CountGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().CountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.Count(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task CountObjectAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<object>().CountAsync());
				Assert.That(result, Is.EqualTo(_totalEntityCount));
				result = await (session.Query<object>().ToFutureValue(qdc => qdc.Count()).GetValueAsync());
				Assert.That(result, Is.EqualTo(_totalEntityCount), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultBBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassBExtendedByA>();
				DomainClassBExtendedByA result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassBExtendedByA>();
				DomainClassBExtendedByA result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultCBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassCExtendedByD>();
				DomainClassCExtendedByD result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassCExtendedByD>();
				DomainClassCExtendedByD result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultEAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassE>();
				DomainClassE result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassE>();
				DomainClassE result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultFAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassF>();
				DomainClassF result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Null);
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Null, "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassF>();
				DomainClassF result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Null);
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Null, "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultGBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassGExtendedByH>();
				DomainClassGExtendedByH result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassGExtendedByH>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassGExtendedByH>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassGExtendedByH>();
				DomainClassGExtendedByH result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassGExtendedByH>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassGExtendedByH>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void FirstOrDefaultObjectAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<object>();
				object result = null;
				Assert.That(async () => result = await (query.FirstOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>());
				var futureQuery = query.ToFutureValue(qdc => qdc.FirstOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				// If class type assert starts failing, maybe just ignore it: order of first on polymorphic queries looks unspecified to me.
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>(), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task LongCountBBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().LongCountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task LongCountBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassBExtendedByA>().LongCountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassBExtendedByA>().ToFutureValue(qdc => qdc.LongCount(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountCBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().LongCountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassCExtendedByD>().LongCountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassCExtendedByD>().ToFutureValue(qdc => qdc.LongCount(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountEAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().LongCountAsync());
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassE>().LongCountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(1));
				result = await (session.Query<DomainClassE>().ToFutureValue(qdc => qdc.LongCount(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountFAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().LongCountAsync());
				Assert.That(result, Is.EqualTo(0));
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(0), "Future");
			}
		}

		// Non-reg case
		[Test]
		public async Task LongCountFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassF>().LongCountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(0));
				result = await (session.Query<DomainClassF>().ToFutureValue(qdc => qdc.LongCount(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(0), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task LongCountGBaseAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().LongCountAsync());
				Assert.That(result, Is.EqualTo(4));
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(4), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task LongCountGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<DomainClassGExtendedByH>().LongCountAsync(dc => dc.Name == _searchName1));
				Assert.That(result, Is.EqualTo(2));
				result = await (session.Query<DomainClassGExtendedByH>().ToFutureValue(qdc => qdc.LongCount(dc => dc.Name == _searchName1)).GetValueAsync());
				Assert.That(result, Is.EqualTo(2), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task LongCountObjectAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<object>().LongCountAsync());
				Assert.That(result, Is.EqualTo(_totalEntityCount));
				result = await (session.Query<object>().ToFutureValue(qdc => qdc.LongCount()).GetValueAsync());
				Assert.That(result, Is.EqualTo(_totalEntityCount), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task MaxBBaseAsync()
		{
			return MaxAsync<DomainClassBExtendedByA>(2);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task MaxCBaseAsync()
		{
			return MaxAsync<DomainClassCExtendedByD>(2);
		}

		// Non-reg case
		[Test]
		public Task MaxEAsync()
		{
			return MaxAsync<DomainClassE>(2);
		}

		// Non-reg case
		[Test]
		public Task MaxFAsync()
		{
			return MaxAsync<DomainClassF>(null);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task MaxGBaseAsync()
		{
			return MaxAsync<DomainClassGExtendedByH>(4);
		}

		private async Task MaxAsync<DC>(int? expectedResult, CancellationToken cancellationToken = default(CancellationToken)) where DC : DomainClassBase
		{
			using (var session = OpenSession())
			{
				var dcQuery = session.Query<DC>();
				var name = await (dcQuery.MaxAsync(dc => dc.Name, cancellationToken));
				Assert.That(name, Is.EqualTo(expectedResult.HasValue ? _searchName2 : null), "String max has failed");
				var futureName = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.Name));
				Assert.That(await (futureName.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult.HasValue ? _searchName2 : null), "Future string max has failed");

				var integ = await (dcQuery.MaxAsync(dc => dc.Integer, cancellationToken));
				Assert.That(integ, Is.EqualTo(expectedResult), "Integer max has failed");
				var futureInteg = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.Integer));
				Assert.That(await (futureInteg.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future integer max has failed");

				var longInt = await (dcQuery.MaxAsync(dc => dc.Long, cancellationToken));
				Assert.That(longInt, Is.EqualTo(expectedResult), "Long integer max has failed");
				var futureLongInt = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.Long));
				Assert.That(await (futureLongInt.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future long integer max has failed");

				var dec = await (dcQuery.MaxAsync(dc => dc.Decimal, cancellationToken));
				Assert.That(dec, Is.EqualTo(expectedResult), "Decimal max has failed");
				var futureDec = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.Decimal));
				Assert.That(await (futureDec.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future decimal max has failed");

				var dbl = await (dcQuery.MaxAsync(dc => dc.Double, cancellationToken));
				Assert.That(dbl.HasValue, Is.EqualTo(expectedResult.HasValue),"Double max has failed");
				if (expectedResult.HasValue)
					Assert.That(dbl.Value, Is.EqualTo(expectedResult).Within(0.001d), "Double max has failed");
				var futureDbl = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.Double));
				Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).HasValue, Is.EqualTo(expectedResult.HasValue),"Future double max has failed");
				if (expectedResult.HasValue)
					Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).Value, Is.EqualTo(expectedResult).Within(0.001d), "Future double max has failed");

				var date = await (dcQuery.MaxAsync(dc => dc.DateTime, cancellationToken));
				var dateWithOffset = await (dcQuery.MaxAsync(dc => dc.DateTimeOffset, cancellationToken));
				var futureDate = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.DateTime));
				var futureDateWithOffset = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.DateTimeOffset));
				if (expectedResult.HasValue)
				{
					Assert.That(date, Is.GreaterThan(_testDate), "DateTime max has failed");
					Assert.That(dateWithOffset, Is.GreaterThan(_testDateWithOffset), "DateTimeOffset max has failed");
					Assert.That(await (futureDate.GetValueAsync(cancellationToken)), Is.GreaterThan(_testDate), "Future DateTime max has failed");
					Assert.That(await (futureDateWithOffset.GetValueAsync(cancellationToken)), Is.GreaterThan(_testDateWithOffset), "Future DateTimeOffset max has failed");
				}
				else
				{
					Assert.That(date, Is.Null, "DateTime max has failed");
					Assert.That(dateWithOffset, Is.Null, "DateTimeOffset max has failed");
					Assert.That(await (futureDate.GetValueAsync(cancellationToken)), Is.Null, "Future DateTime max has failed");
					Assert.That(await (futureDateWithOffset.GetValueAsync(cancellationToken)), Is.Null, "Future DateTimeOffset max has failed");
				}

				if (expectedResult.HasValue)
				{
					var nonNullableDecimal = -1m;
					Assert.That(async () => nonNullableDecimal = await (dcQuery.MaxAsync(dc => dc.NonNullableDecimal, cancellationToken)), Throws.Nothing, "Non nullable decimal max has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Non nullable decimal max has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.NonNullableDecimal));
					Assert.That(async () => nonNullableDecimal = await (futureNonNullableDec.GetValueAsync(cancellationToken)), Throws.Nothing, "Future non nullable decimal max has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Future non nullable decimal max has failed");
				}
				else
				{
					Assert.That(() => dcQuery.MaxAsync(dc => dc.NonNullableDecimal, cancellationToken),
					            // After fix
					            Throws.InstanceOf<InvalidOperationException>()
					                  // Before fix
					                  .Or.InnerException.InstanceOf<ArgumentNullException>(),
					            "Non nullable decimal max has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Max(dc => dc.NonNullableDecimal));
					Assert.That(() => futureNonNullableDec.GetValueAsync(cancellationToken),
					            Throws.TargetInvocationException.And.InnerException.InstanceOf<InvalidOperationException>(),
					            "Future non nullable decimal max has failed");
				}
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task MinBBaseAsync()
		{
			return MinAsync<DomainClassBExtendedByA>(1);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task MinCBaseAsync()
		{
			return MinAsync<DomainClassCExtendedByD>(1);
		}

		// Non-reg case
		[Test]
		public Task MinEAsync()
		{
			return MinAsync<DomainClassE>(1);
		}

		// Non-reg case
		[Test]
		public Task MinFAsync()
		{
			return MinAsync<DomainClassF>(null);
		}

		// Non-reg case
		[Test]
		public Task MinGBaseAsync()
		{
			return MinAsync<DomainClassGExtendedByH>(1);
		}

		private async Task MinAsync<DC>(int? expectedResult, CancellationToken cancellationToken = default(CancellationToken)) where DC : DomainClassBase
		{
			using (var session = OpenSession())
			{
				var dcQuery = session.Query<DC>();
				var name = await (dcQuery.MinAsync(dc => dc.Name, cancellationToken));
				Assert.That(name, Is.EqualTo(expectedResult.HasValue ? _searchName1 : null), "String min has failed");
				var futureName = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.Name));
				Assert.That(await (futureName.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult.HasValue ? _searchName1 : null), "Future string min has failed");

				var integ = await (dcQuery.MinAsync(dc => dc.Integer, cancellationToken));
				Assert.That(integ, Is.EqualTo(expectedResult), "Integer min has failed");
				var futureInteg = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.Integer));
				Assert.That(await (futureInteg.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future integer min has failed");

				var longInt = await (dcQuery.MinAsync(dc => dc.Long, cancellationToken));
				Assert.That(longInt, Is.EqualTo(expectedResult), "Long integer min has failed");
				var futureLongInt = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.Long));
				Assert.That(await (futureLongInt.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future long integer min has failed");

				var dec = await (dcQuery.MinAsync(dc => dc.Decimal, cancellationToken));
				Assert.That(dec, Is.EqualTo(expectedResult), "Decimal min has failed");
				var futureDec = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.Decimal));
				Assert.That(await (futureDec.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future decimal min has failed");

				var dbl = await (dcQuery.MinAsync(dc => dc.Double, cancellationToken));
				Assert.That(dbl.HasValue, Is.EqualTo(expectedResult.HasValue),"Double min has failed");
				if (expectedResult.HasValue)
					Assert.That(dbl.Value, Is.EqualTo(expectedResult).Within(0.001d), "Double min has failed");
				var futureDbl = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.Double));
				Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).HasValue, Is.EqualTo(expectedResult.HasValue),"Future double min has failed");
				if (expectedResult.HasValue)
					Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).Value, Is.EqualTo(expectedResult).Within(0.001d), "Future double min has failed");

				var date = await (dcQuery.MinAsync(dc => dc.DateTime, cancellationToken));
				var dateWithOffset = await (dcQuery.MinAsync(dc => dc.DateTimeOffset, cancellationToken));
				var futureDate = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.DateTime));
				var futureDateWithOffset = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.DateTimeOffset));
				if (expectedResult.HasValue)
				{
					Assert.That(date, Is.LessThan(_testDate), "DateTime min has failed");
					Assert.That(dateWithOffset, Is.LessThan(_testDateWithOffset), "DateTimeOffset min has failed");
					Assert.That(await (futureDate.GetValueAsync(cancellationToken)), Is.LessThan(_testDate), "Future DateTime min has failed");
					Assert.That(await (futureDateWithOffset.GetValueAsync(cancellationToken)), Is.LessThan(_testDateWithOffset), "Future DateTimeOffset min has failed");
				}
				else
				{
					Assert.That(date, Is.Null, "DateTime min has failed");
					Assert.That(dateWithOffset, Is.Null, "DateTimeOffset min has failed");
					Assert.That(await (futureDate.GetValueAsync(cancellationToken)), Is.Null, "Future DateTime min has failed");
					Assert.That(await (futureDateWithOffset.GetValueAsync(cancellationToken)), Is.Null, "Future DateTimeOffset min has failed");
				}

				if (expectedResult.HasValue)
				{
					var nonNullableDecimal = -1m;
					Assert.That(async () => nonNullableDecimal = await (dcQuery.MinAsync(dc => dc.NonNullableDecimal, cancellationToken)), Throws.Nothing, "Non nullable decimal min has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Non nullable decimal min has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.NonNullableDecimal));
					Assert.That(async () => nonNullableDecimal = await (futureNonNullableDec.GetValueAsync(cancellationToken)), Throws.Nothing, "Future non nullable decimal min has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Future non nullable decimal min has failed");
				}
				else
				{
					Assert.That(() => dcQuery.MinAsync(dc => dc.NonNullableDecimal, cancellationToken),
					            // After fix
					            Throws.InstanceOf<InvalidOperationException>()
					                  // Before fix
					                  .Or.InnerException.InstanceOf<ArgumentNullException>(),
					            "Non nullable decimal min has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Min(dc => dc.NonNullableDecimal));
					Assert.That(() => futureNonNullableDec.GetValueAsync(cancellationToken),
					            Throws.TargetInvocationException.And.InnerException.InstanceOf<InvalidOperationException>(),
					            "Future non nullable decimal min has failed");
				}
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultBBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassBExtendedByA>();
				Assert.That(() => query.SingleOrDefaultAsync(), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultBBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassBExtendedByA>();
				DomainClassBExtendedByA result = null;
				Assert.That(async () => result = await (query.SingleOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>());
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
				Assert.That(result, Is.TypeOf<DomainClassBExtendedByA>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultCBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassCExtendedByD>();
				Assert.That(() => query.SingleOrDefaultAsync(), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultCBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassCExtendedByD>();
				DomainClassCExtendedByD result = null;
				Assert.That(async () => result = await (query.SingleOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>());
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
				Assert.That(result, Is.TypeOf<DomainClassCExtendedByD>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultEAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassE>();
				Assert.That(() => query.SingleOrDefaultAsync(), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultEWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassE>();
				DomainClassE result = null;
				Assert.That(async () => result = await (query.SingleOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Not.Null);
				Assert.That(result.Name, Is.EqualTo(_searchName1));
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Not.Null, "Future");
				Assert.That(result.Name, Is.EqualTo(_searchName1), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultFAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassF>();
				DomainClassF result = null;
				Assert.That(async () => result = await (query.SingleOrDefaultAsync()), Throws.Nothing);
				Assert.That(result, Is.Null);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Null, "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultFWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassF>();
				DomainClassF result = null;
				Assert.That(async () => result = await (query.SingleOrDefaultAsync(dc => dc.Name == _searchName1)), Throws.Nothing);
				Assert.That(result, Is.Null);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault(dc => dc.Name == _searchName1));
				Assert.That(async () => result = await (futureQuery.GetValueAsync()), Throws.Nothing, "Future");
				Assert.That(result, Is.Null, "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultGBaseAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassGExtendedByH>();
				Assert.That(() => query.SingleOrDefaultAsync(), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultGBaseWithNameAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<DomainClassGExtendedByH>();
				Assert.That(() => query.SingleOrDefaultAsync(dc => dc.Name == _searchName1), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault(dc => dc.Name == _searchName1));
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Non-reg case
		[Test]
		public void SingleOrDefaultObjectAsync()
		{
			using (var session = OpenSession())
			{
				var query = session.Query<object>();
				Assert.That(() => query.SingleOrDefaultAsync(), Throws.InvalidOperationException);
				var futureQuery = query.ToFutureValue(qdc => qdc.SingleOrDefault());
				Assert.That(() => futureQuery.GetValueAsync(), Throws.TargetInvocationException.And.InnerException.TypeOf<InvalidOperationException>(), "Future");
			}
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task SumBBaseAsync()
		{
			return SumAsync<DomainClassBExtendedByA>(3);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task SumCBaseAsync()
		{
			return SumAsync<DomainClassCExtendedByD>(3);
		}

		// Non-reg case
		[Test]
		public Task SumEAsync()
		{
			return SumAsync<DomainClassE>(3);
		}

		// Non-reg case
		[Test]
		public Task SumFAsync()
		{
			return SumAsync<DomainClassF>(null);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public Task SumGBaseAsync()
		{
			return SumAsync<DomainClassGExtendedByH>(10);
		}

		// Failing case till NH-3850 is fixed
		[Test]
		public async Task SumObjectAsync()
		{
			using (var session = OpenSession())
			{
				var result = await (session.Query<object>().SumAsync(o => (int?)2));
				Assert.That(result, Is.EqualTo(_totalEntityCount * 2));
			}
		}

		private async Task SumAsync<DC>(int? expectedResult, CancellationToken cancellationToken = default(CancellationToken)) where DC : DomainClassBase
		{
			using (var session = OpenSession())
			{
				var dcQuery = session.Query<DC>();
				var integ = await (dcQuery.SumAsync(dc => dc.Integer, cancellationToken));
				Assert.That(integ, Is.EqualTo(expectedResult), "Integer sum has failed");
				var futureInteg = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.Integer));
				Assert.That(await (futureInteg.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future integer sum has failed");

				var longInt = await (dcQuery.SumAsync(dc => dc.Long, cancellationToken));
				Assert.That(longInt, Is.EqualTo(expectedResult), "Long integer sum has failed");
				var futureLongInt = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.Long));
				Assert.That(await (futureLongInt.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future long integer sum has failed");

				var dec = await (dcQuery.SumAsync(dc => dc.Decimal, cancellationToken));
				Assert.That(dec, Is.EqualTo(expectedResult), "Decimal sum has failed");
				var futureDec = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.Decimal));
				Assert.That(await (futureDec.GetValueAsync(cancellationToken)), Is.EqualTo(expectedResult), "Future decimal sum has failed");

				var dbl = await (dcQuery.SumAsync(dc => dc.Double, cancellationToken));
				Assert.That(dbl.HasValue, Is.EqualTo(expectedResult.HasValue), "Double sum has failed");
				if (expectedResult.HasValue)
					Assert.That(dbl.Value, Is.EqualTo(expectedResult).Within(0.001d), "Double sum has failed");
				var futureDbl = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.Double));
				Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).HasValue, Is.EqualTo(expectedResult.HasValue), "Future double sum has failed");
				if (expectedResult.HasValue)
					Assert.That((await (futureDbl.GetValueAsync(cancellationToken))).Value, Is.EqualTo(expectedResult).Within(0.001d), "Future double sum has failed");

				if (expectedResult.HasValue)
				{
					var nonNullableDecimal = -1m;
					Assert.That(async () => nonNullableDecimal = await (dcQuery.SumAsync(dc => dc.NonNullableDecimal, cancellationToken)), Throws.Nothing, "Non nullable decimal sum has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Non nullable decimal sum has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.NonNullableDecimal));
					Assert.That(async () => nonNullableDecimal = await (futureNonNullableDec.GetValueAsync(cancellationToken)), Throws.Nothing, "Future non nullable decimal sum has failed");
					Assert.That(nonNullableDecimal, Is.EqualTo(expectedResult), "Future non nullable decimal sum has failed");
				}
				else
				{
					Assert.That(() => dcQuery.SumAsync(dc => dc.NonNullableDecimal, cancellationToken),
					            // After fix
					            Throws.InstanceOf<InvalidOperationException>()
					                  // Before fix
					                  .Or.InnerException.InstanceOf<ArgumentNullException>(),
					            "Non nullable decimal sum has failed");
					var futureNonNullableDec = dcQuery.ToFutureValue(qdc => qdc.Sum(dc => dc.NonNullableDecimal));
					Assert.That(() => futureNonNullableDec.GetValueAsync(cancellationToken),
					            Throws.TargetInvocationException.And.InnerException.InstanceOf<InvalidOperationException>(),
					            "Future non nullable decimal sum has failed");
				}
			}
		}
	}
}
