From 722d1264e7611cf7a61a2ff4ecd6768857a8e5aa Mon Sep 17 00:00:00 2001 From: Christopher Jolly Date: Mon, 15 Jan 2024 23:04:56 +0800 Subject: [PATCH] Fix tests based on BuiltInDataTypes. There is not millisecond support for time based data types and no offset on the DateTimeOffset. We need to override the full test and all of its helper functions as the test values are hard coded inside --- .../BuiltInDataTypesJetTest.cs | 1234 ++++++++++++++++ .../ConvertToProviderTypesJetTest.cs | 1235 +++++++++++++++++ .../CustomConvertersJetTest.cs | 321 +++++ 3 files changed, 2790 insertions(+) diff --git a/test/EFCore.Jet.FunctionalTests/BuiltInDataTypesJetTest.cs b/test/EFCore.Jet.FunctionalTests/BuiltInDataTypesJetTest.cs index 4d90917..3481650 100644 --- a/test/EFCore.Jet.FunctionalTests/BuiltInDataTypesJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/BuiltInDataTypesJetTest.cs @@ -6,10 +6,12 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Text; using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities; using EntityFrameworkCore.Jet.Infrastructure; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -4413,5 +4415,1237 @@ UnicodeDataTypes.StringUnicode ---> [nullable varchar] [MaxLength = 255] public int? NumericScale { get; set; } public int? DateTimePrecision { get; set; } } + + public override void Can_insert_and_read_back_all_non_nullable_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new BuiltInDataTypes + { + Id = 1, + PartitionId = 1, + TestInt16 = -1234, + TestInt32 = -123456789, + TestInt64 = -1234567890123456789L, + TestDouble = -1.23456789, + TestDecimal = -1234567890.01M, + TestDateTime = DateTime.Parse("01/01/2000 12:34:56", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal), + TestDateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TestTimeSpan = new TimeSpan(0, 10, 9, 8, 0), + TestDateOnly = new DateOnly(2020, 3, 1), + TestTimeOnly = new TimeOnly(12, 30, 45, 0), + TestSingle = -1.234F, + TestBoolean = true, + TestByte = 255, + TestUnsignedInt16 = 1234, + TestUnsignedInt32 = 1234565789U, + TestUnsignedInt64 = 1234567890123456789UL, + TestCharacter = 'a', + TestSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(e => e.Id == 1).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(BuiltInDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.TestInt16); + AssertEqualIfMapped(entityType, -123456789, () => dt.TestInt32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.TestInt64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.TestDouble); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.TestDecimal); + AssertEqualIfMapped( + entityType, DateTime.Parse("01/01/2000 12:34:56", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal), + () => dt.TestDateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.TestDateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TestTimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.TestDateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TestTimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.TestSingle); + AssertEqualIfMapped(entityType, true, () => dt.TestBoolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.TestByte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.TestUnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.TestUnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.TestUnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.TestCharacter); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.TestSignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_all_nullable_data_types_with_values_set_to_non_null() + { + using (var context = CreateContext()) + { + context.Set().Add( + new BuiltInNullableDataTypes + { + Id = 101, + PartitionId = 101, + TestString = "TestString", + TestByteArray = new byte[] { 10, 9, 8, 7, 6 }, + TestNullableInt16 = -1234, + TestNullableInt32 = -123456789, + TestNullableInt64 = -1234567890123456789L, + TestNullableDouble = -1.23456789, + TestNullableDecimal = -1234567890.01M, + TestNullableDateTime = DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), + TestNullableDateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TestNullableDateOnly = new DateOnly(2020, 3, 1), + TestNullableTimeOnly = new TimeOnly(12, 30, 45, 0), + TestNullableTimeSpan = new TimeSpan(0, 10, 9, 8, 0), + TestNullableSingle = -1.234F, + TestNullableBoolean = false, + TestNullableByte = 255, + TestNullableUnsignedInt16 = 1234, + TestNullableUnsignedInt32 = 1234565789U, + TestNullableUnsignedInt64 = 1234567890123456789UL, + TestNullableCharacter = 'a', + TestNullableSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(BuiltInNullableDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.TestString); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.TestByteArray); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.TestNullableInt16); + AssertEqualIfMapped(entityType, -123456789, () => dt.TestNullableInt32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.TestNullableInt64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.TestNullableDouble); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.TestNullableDecimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), () => dt.TestNullableDateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.TestNullableDateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TestNullableTimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.TestNullableDateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TestNullableTimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.TestNullableSingle); + AssertEqualIfMapped(entityType, false, () => dt.TestNullableBoolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.TestNullableByte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.TestNullableUnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.TestNullableUnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.TestNullableUnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.TestNullableCharacter); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.TestNullableSignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_object_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new ObjectBackedDataTypes + { + Id = 101, + PartitionId = 101, + String = "TestString", + Bytes = new byte[] { 10, 9, 8, 7, 6 }, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(ObjectBackedDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.String); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.Bytes); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_non_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NonNullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = true, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NonNullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, true, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_query_using_any_data_type() + { + using var context = CreateContext(); + var source = AddTestBuiltInDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInDataTypesTest(source); + } + + public override void Can_query_using_any_data_type_shadow() + { + using var context = CreateContext(); + var source = AddTestBuiltInDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInDataTypesTest(source); + } + + private void QueryBuiltInDataTypesTest(EntityEntry source) + where TEntity : BuiltInDataTypesBase + { + using var context = CreateContext(); + var set = context.Set(); + var entity = set.Where(e => e.Id == 11).ToList().Single(); + var entityType = context.Model.FindEntityType(typeof(TEntity)); + + var param1 = (short)-1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt16)) == param1).ToList().Single()); + + var param2 = -123456789; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt32)) == param2).ToList().Single()); + + var param3 = -1234567890123456789L; + if (Fixture.IntegerPrecision == 64) + { + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt64)) == param3).ToList().Single()); + } + + double? param4 = -1.23456789; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) == param4).ToList().Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + double? param4l = -1.234567891; + double? param4h = -1.234567889; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) == param4 + || (EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) > param4l + && EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) < param4h))) + .ToList().Single()); + } + + var param5 = -1234567890.01M; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDecimal)) == param5).ToList() + .Single()); + + var param6 = Fixture.DefaultDateTime; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateTime)) == param6).ToList() + .Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestDateTimeOffset)) != null) + { + var param7 = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateTimeOffset)) == param7) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestTimeSpan)) != null) + { + var param8 = new TimeSpan(0, 10, 9, 8, 7); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestTimeSpan)) == param8).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestDateOnly)) != null) + { + var param9 = new DateOnly(2020, 3, 1); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateOnly)) == param9).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestTimeOnly)) != null) + { + var param10 = new TimeOnly(12, 30, 45, 0); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestTimeOnly)) == param10).ToList() + .Single()); + } + + var param11 = -1.234F; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) == param11).ToList().Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + var param11l = -1.2341F; + var param11h = -1.2339F; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) == param11 + || (EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) > param11l + && EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) < param11h))).ToList().Single()); + } + + var param12 = true; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestBoolean)) == param12).ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestByte)) != null) + { + var param13 = (byte)255; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestByte)) == param13).ToList().Single()); + } + + var param14 = Enum64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == param14).ToList().Single()); + + var param15 = Enum32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == param15).ToList().Single()); + + var param16 = Enum16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == param16).ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.Enum8)) != null) + { + var param17 = Enum8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == param17).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt16)) != null) + { + var param18 = (ushort)1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt16)) == param18).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt32)) != null) + { + var param19 = 1234565789U; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt32)) == param19).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt64)) != null) + { + var param20 = 1234567890123456789UL; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt64)) == param20).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestCharacter)) != null) + { + var param21 = 'a'; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestCharacter)) == param21).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestSignedByte)) != null) + { + var param22 = (sbyte)-128; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestSignedByte)) == param22).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU64)) != null) + { + var param23 = EnumU64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU64)) == param23).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU32)) != null) + { + var param24 = EnumU32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU32)) == param24).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU16)) != null) + { + var param25 = EnumU16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU16)) == param25).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumS8)) != null) + { + var param26 = EnumS8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumS8)) == param26).ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum64))?.GetProviderClrType()) == typeof(long)) + { + var param27 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == (Enum64)param27).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == param27).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum32))?.GetProviderClrType()) == typeof(int)) + { + var param28 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == (Enum32)param28).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == param28).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum16))?.GetProviderClrType()) == typeof(short)) + { + var param29 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == (Enum16)param29).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == param29).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum8))?.GetProviderClrType()) == typeof(byte)) + { + var param30 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == (Enum8)param30).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == param30).ToList() + .Single()); + } + + foreach (var propertyEntry in context.Entry(entity).Properties) + { + if (propertyEntry.Metadata.ValueGenerated != ValueGenerated.Never) + { + continue; + } + + Assert.Equal( + source.Property(propertyEntry.Metadata).CurrentValue, + propertyEntry.CurrentValue); + } + } + + protected new EntityEntry AddTestBuiltInDataTypes(DbSet set) + where TEntity : BuiltInDataTypesBase, new() + { + var entityEntry = set.Add( + new TEntity { Id = 11 }); + + entityEntry.CurrentValues.SetValues( + new BuiltInDataTypes + { + Id = 11, + PartitionId = 1, + TestInt16 = -1234, + TestInt32 = -123456789, + TestInt64 = -1234567890123456789L, + TestDouble = -1.23456789, + TestDecimal = -1234567890.01M, + TestDateTime = Fixture.DefaultDateTime, + TestDateTimeOffset = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)), + TestTimeSpan = new TimeSpan(0, 10, 9, 8, 7), + TestDateOnly = new DateOnly(2020, 3, 1), + TestTimeOnly = new TimeOnly(12, 30, 45, 0), + TestSingle = -1.234F, + TestBoolean = true, + TestByte = 255, + TestUnsignedInt16 = 1234, + TestUnsignedInt32 = 1234565789U, + TestUnsignedInt64 = 1234567890123456789UL, + TestCharacter = 'a', + TestSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + return entityEntry; + } + + public override void Can_query_using_any_nullable_data_type() + { + using var context = CreateContext(); + var source = AddTestBuiltInNullableDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInNullableDataTypesTest(source); + } + + public override void Can_query_using_any_data_type_nullable_shadow() + { + using var context = CreateContext(); + var source = AddTestBuiltInNullableDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInNullableDataTypesTest(source); + } + + private void QueryBuiltInNullableDataTypesTest(EntityEntry source) + where TEntity : BuiltInNullableDataTypesBase + { + using var context = CreateContext(); + var set = context.Set(); + var entity = set.Where(e => e.Id == 11).ToList().Single(); + var entityType = context.Model.FindEntityType(typeof(TEntity)); + + short? param1 = -1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt16)) == param1) + .ToList().Single()); + + int? param2 = -123456789; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt32)) == param2) + .ToList().Single()); + + long? param3 = -1234567890123456789L; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt64)) == param3) + .ToList().Single()); + + double? param4 = -1.23456789; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) == param4).ToList() + .Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + double? param4l = -1.234567891; + double? param4h = -1.234567889; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) == param4 + || (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) > param4l + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) < param4h))) + .ToList().Single()); + } + + decimal? param5 = -1234567890.01M; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDecimal)) == param5) + .ToList().Single()); + + DateTime? param6 = Fixture.DefaultDateTime; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateTime)) == param6) + .ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableDateTimeOffset)) != null) + { + DateTimeOffset? param7 = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateTimeOffset)) + == param7).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableTimeSpan)) != null) + { + TimeSpan? param8 = new TimeSpan(0, 10, 9, 8, 7); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableTimeSpan)) + == param8) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableDateOnly)) != null) + { + DateOnly? param9 = new DateOnly(2020, 3, 1); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateOnly)) + == param9) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableTimeOnly)) != null) + { + TimeOnly? param10 = new TimeOnly(12, 30, 45, 0); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableTimeOnly)) + == param10) + .ToList().Single()); + } + + float? param11 = -1.234F; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) == param11).ToList() + .Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + float? param11l = -1.2341F; + float? param11h = -1.2339F; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) == param11 + || (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) > param11l + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) < param11h))) + .ToList().Single()); + } + + bool? param12 = true; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableBoolean)) == param12) + .ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableByte)) != null) + { + byte? param13 = 255; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableByte)) == param13) + .ToList().Single()); + } + + Enum64? param14 = Enum64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == param14).ToList() + .Single()); + + Enum32? param15 = Enum32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == param15).ToList() + .Single()); + + Enum16? param16 = Enum16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == param16).ToList() + .Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum8)) != null) + { + Enum8? param17 = Enum8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == param17).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt16)) != null) + { + ushort? param18 = 1234; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt16)) + == param18).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt32)) != null) + { + uint? param19 = 1234565789U; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt32)) + == param19) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt64)) != null) + { + ulong? param20 = 1234567890123456789UL; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property( + e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt64)) + == param20).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableCharacter)) != null) + { + char? param21 = 'a'; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableCharacter)) == param21) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableSignedByte)) != null) + { + sbyte? param22 = -128; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSignedByte)) + == param22) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU64)) != null) + { + var param23 = EnumU64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU64)) == param23).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU32)) != null) + { + var param24 = EnumU32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU32)) == param24).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU16)) != null) + { + var param25 = EnumU16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU16)) == param25).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumS8)) != null) + { + var param26 = EnumS8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumS8)) == param26).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum64))?.GetProviderClrType()) + == typeof(long)) + { + int? param27 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == (Enum64)param27) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == param27) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum32))?.GetProviderClrType()) + == typeof(int)) + { + int? param28 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == (Enum32)param28) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == param28) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum16))?.GetProviderClrType()) + == typeof(short)) + { + int? param29 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == (Enum16)param29) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == param29) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum8))?.GetProviderClrType()) + == typeof(byte)) + { + int? param30 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == (Enum8)param30) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == param30) + .ToList().Single()); + } + + foreach (var propertyEntry in context.Entry(entity).Properties) + { + if (propertyEntry.Metadata.ValueGenerated != ValueGenerated.Never) + { + continue; + } + + Assert.Equal( + source.Property(propertyEntry.Metadata).CurrentValue, + propertyEntry.CurrentValue); + } + } + + protected new virtual EntityEntry AddTestBuiltInNullableDataTypes(DbSet set) + where TEntity : BuiltInNullableDataTypesBase, new() + { + var entityEntry = set.Add( + new TEntity { Id = 11 }); + + entityEntry.CurrentValues.SetValues( + new BuiltInNullableDataTypes + { + Id = 11, + PartitionId = 1, + TestNullableInt16 = -1234, + TestNullableInt32 = -123456789, + TestNullableInt64 = -1234567890123456789L, + TestNullableDouble = -1.23456789, + TestNullableDecimal = -1234567890.01M, + TestNullableDateTime = Fixture.DefaultDateTime, + TestNullableDateTimeOffset = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)), + TestNullableTimeSpan = new TimeSpan(0, 10, 9, 8, 7), + TestNullableDateOnly = new DateOnly(2020, 3, 1), + TestNullableTimeOnly = new TimeOnly(12, 30, 45, 0), + TestNullableSingle = -1.234F, + TestNullableBoolean = true, + TestNullableByte = 255, + TestNullableUnsignedInt16 = 1234, + TestNullableUnsignedInt32 = 1234565789U, + TestNullableUnsignedInt64 = 1234567890123456789UL, + TestNullableCharacter = 'a', + TestNullableSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + return entityEntry; + } + + + + private void AssertEqualIfMapped(IEntityType entityType, T expected, Expression> actualExpression) + { + if (entityType.FindProperty(((MemberExpression)actualExpression.Body).Member.Name) != null) + { + var actual = actualExpression.Compile()(); + var type = UnwrapNullableEnumType(typeof(T)); + if (IsSignedInteger(type)) + { + Assert.True(Equal(Convert.ToInt64(expected), Convert.ToInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (IsUnsignedInteger(type)) + { + Assert.True(Equal(Convert.ToUInt64(expected), Convert.ToUInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (type == typeof(DateTime)) + { + Assert.True( + Equal((DateTime)(object)expected, (DateTime)(object)actual), $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else if (type == typeof(DateTimeOffset)) + { + Assert.True( + Equal((DateTimeOffset)(object)expected, (DateTimeOffset)(object)actual), + $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else + { + Assert.Equal(expected, actual); + } + } + } + + private bool Equal(long left, long right) + { + if (left >= 0 + && right >= 0) + { + return Equal((ulong)left, (ulong)right); + } + + if (left < 0 + && right < 0) + { + return Equal((ulong)-left, (ulong)-right); + } + + return false; + } + + private bool Equal(ulong left, ulong right) + { + if (Fixture.IntegerPrecision < 64) + { + var largestPrecise = 1ul << Fixture.IntegerPrecision; + while (left > largestPrecise) + { + left >>= 1; + right >>= 1; + } + } + + return left == right; + } + + private bool Equal(DateTime left, DateTime right) + => left.Equals(right) && (!Fixture.PreservesDateTimeKind || left.Kind == right.Kind); + + private bool Equal(DateTimeOffset left, DateTimeOffset right) + => left.EqualsExact(right); + + private static Type UnwrapNullableType(Type type) + => type == null ? null : Nullable.GetUnderlyingType(type) ?? type; + + private static bool IsSignedInteger(Type type) + => type == typeof(int) + || type == typeof(long) + || type == typeof(short) + || type == typeof(sbyte); + + private static bool IsUnsignedInteger(Type type) + => type == typeof(byte) + || type == typeof(uint) + || type == typeof(ulong) + || type == typeof(ushort) + || type == typeof(char); } } diff --git a/test/EFCore.Jet.FunctionalTests/ConvertToProviderTypesJetTest.cs b/test/EFCore.Jet.FunctionalTests/ConvertToProviderTypesJetTest.cs index dd01a0a..2dd644c 100644 --- a/test/EFCore.Jet.FunctionalTests/ConvertToProviderTypesJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/ConvertToProviderTypesJetTest.cs @@ -1,11 +1,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Globalization; using System.Linq; +using System.Linq.Expressions; using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -180,6 +183,1238 @@ UnicodeDataTypes.StringUnicode ---> [nullable varchar] [MaxLength = 255] Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); } + public override void Can_insert_and_read_back_all_non_nullable_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new BuiltInDataTypes + { + Id = 1, + PartitionId = 1, + TestInt16 = -1234, + TestInt32 = -123456789, + TestInt64 = -1234567890123456789L, + TestDouble = -1.23456789, + TestDecimal = -1234567890.01M, + TestDateTime = DateTime.Parse("01/01/2000 12:34:56", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal), + TestDateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TestTimeSpan = new TimeSpan(0, 10, 9, 8, 0), + TestDateOnly = new DateOnly(2020, 3, 1), + TestTimeOnly = new TimeOnly(12, 30, 45, 0), + TestSingle = -1.234F, + TestBoolean = true, + TestByte = 255, + TestUnsignedInt16 = 1234, + TestUnsignedInt32 = 1234565789U, + TestUnsignedInt64 = 1234567890123456789UL, + TestCharacter = 'a', + TestSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(e => e.Id == 1).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(BuiltInDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.TestInt16); + AssertEqualIfMapped(entityType, -123456789, () => dt.TestInt32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.TestInt64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.TestDouble); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.TestDecimal); + AssertEqualIfMapped( + entityType, DateTime.Parse("01/01/2000 12:34:56", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal), + () => dt.TestDateTime); + AssertEqualIfMapped( + entityType, new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + () => dt.TestDateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TestTimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.TestDateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TestTimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.TestSingle); + AssertEqualIfMapped(entityType, true, () => dt.TestBoolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.TestByte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.TestUnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.TestUnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.TestUnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.TestCharacter); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.TestSignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_all_nullable_data_types_with_values_set_to_non_null() + { + using (var context = CreateContext()) + { + context.Set().Add( + new BuiltInNullableDataTypes + { + Id = 101, + PartitionId = 101, + TestString = "TestString", + TestByteArray = new byte[] { 10, 9, 8, 7, 6 }, + TestNullableInt16 = -1234, + TestNullableInt32 = -123456789, + TestNullableInt64 = -1234567890123456789L, + TestNullableDouble = -1.23456789, + TestNullableDecimal = -1234567890.01M, + TestNullableDateTime = DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), + TestNullableDateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TestNullableDateOnly = new DateOnly(2020, 3, 1), + TestNullableTimeOnly = new TimeOnly(12, 30, 45, 0), + TestNullableTimeSpan = new TimeSpan(0, 10, 9, 8, 0), + TestNullableSingle = -1.234F, + TestNullableBoolean = false, + TestNullableByte = 255, + TestNullableUnsignedInt16 = 1234, + TestNullableUnsignedInt32 = 1234565789U, + TestNullableUnsignedInt64 = 1234567890123456789UL, + TestNullableCharacter = 'a', + TestNullableSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(BuiltInNullableDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.TestString); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.TestByteArray); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.TestNullableInt16); + AssertEqualIfMapped(entityType, -123456789, () => dt.TestNullableInt32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.TestNullableInt64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.TestNullableDouble); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.TestNullableDecimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), () => dt.TestNullableDateTime); + AssertEqualIfMapped( + entityType, new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + () => dt.TestNullableDateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TestNullableTimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.TestNullableDateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TestNullableTimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.TestNullableSingle); + AssertEqualIfMapped(entityType, false, () => dt.TestNullableBoolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.TestNullableByte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.TestNullableUnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.TestNullableUnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.TestNullableUnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.TestNullableCharacter); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.TestNullableSignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_object_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new ObjectBackedDataTypes + { + Id = 101, + PartitionId = 101, + String = "TestString", + Bytes = new byte[] { 10, 9, 8, 7, 6 }, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(ObjectBackedDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.String); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.Bytes); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_non_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NonNullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = true, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NonNullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, true, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_query_using_any_data_type() + { + using var context = CreateContext(); + var source = AddTestBuiltInDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInDataTypesTest(source); + } + + public override void Can_query_using_any_data_type_shadow() + { + using var context = CreateContext(); + var source = AddTestBuiltInDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInDataTypesTest(source); + } + + private void QueryBuiltInDataTypesTest(EntityEntry source) + where TEntity : BuiltInDataTypesBase + { + using var context = CreateContext(); + var set = context.Set(); + var entity = set.Where(e => e.Id == 11).ToList().Single(); + var entityType = context.Model.FindEntityType(typeof(TEntity)); + + var param1 = (short)-1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt16)) == param1).ToList().Single()); + + var param2 = -123456789; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt32)) == param2).ToList().Single()); + + var param3 = -1234567890123456789L; + if (Fixture.IntegerPrecision == 64) + { + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestInt64)) == param3).ToList().Single()); + } + + double? param4 = -1.23456789; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) == param4).ToList().Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + double? param4l = -1.234567891; + double? param4h = -1.234567889; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) == param4 + || (EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) > param4l + && EF.Property(e, nameof(BuiltInDataTypes.TestDouble)) < param4h))) + .ToList().Single()); + } + + var param5 = -1234567890.01M; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDecimal)) == param5).ToList() + .Single()); + + var param6 = Fixture.DefaultDateTime; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateTime)) == param6).ToList() + .Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestDateTimeOffset)) != null) + { + var param7 = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateTimeOffset)) == param7) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestTimeSpan)) != null) + { + var param8 = new TimeSpan(0, 10, 9, 8, 7); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestTimeSpan)) == param8).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestDateOnly)) != null) + { + var param9 = new DateOnly(2020, 3, 1); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestDateOnly)) == param9).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestTimeOnly)) != null) + { + var param10 = new TimeOnly(12, 30, 45, 0); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestTimeOnly)) == param10).ToList() + .Single()); + } + + var param11 = -1.234F; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) == param11).ToList().Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + var param11l = -1.2341F; + var param11h = -1.2339F; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) == param11 + || (EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) > param11l + && EF.Property(e, nameof(BuiltInDataTypes.TestSingle)) < param11h))).ToList().Single()); + } + + var param12 = true; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestBoolean)) == param12).ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestByte)) != null) + { + var param13 = (byte)255; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestByte)) == param13).ToList().Single()); + } + + var param14 = Enum64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == param14).ToList().Single()); + + var param15 = Enum32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == param15).ToList().Single()); + + var param16 = Enum16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == param16).ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInDataTypes.Enum8)) != null) + { + var param17 = Enum8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == param17).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt16)) != null) + { + var param18 = (ushort)1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt16)) == param18).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt32)) != null) + { + var param19 = 1234565789U; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt32)) == param19).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestUnsignedInt64)) != null) + { + var param20 = 1234567890123456789UL; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestUnsignedInt64)) == param20).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestCharacter)) != null) + { + var param21 = 'a'; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestCharacter)) == param21).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.TestSignedByte)) != null) + { + var param22 = (sbyte)-128; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.TestSignedByte)) == param22).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU64)) != null) + { + var param23 = EnumU64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU64)) == param23).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU32)) != null) + { + var param24 = EnumU32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU32)) == param24).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumU16)) != null) + { + var param25 = EnumU16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumU16)) == param25).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInDataTypes.EnumS8)) != null) + { + var param26 = EnumS8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.EnumS8)) == param26).ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum64))?.GetProviderClrType()) == typeof(long)) + { + var param27 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == (Enum64)param27).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum64)) == param27).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum32))?.GetProviderClrType()) == typeof(int)) + { + var param28 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == (Enum32)param28).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum32)) == param28).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum16))?.GetProviderClrType()) == typeof(short)) + { + var param29 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == (Enum16)param29).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum16)) == param29).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInDataTypes.Enum8))?.GetProviderClrType()) == typeof(byte)) + { + var param30 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == (Enum8)param30).ToList() + .Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInDataTypes.Enum8)) == param30).ToList() + .Single()); + } + + foreach (var propertyEntry in context.Entry(entity).Properties) + { + if (propertyEntry.Metadata.ValueGenerated != ValueGenerated.Never) + { + continue; + } + + Assert.Equal( + source.Property(propertyEntry.Metadata).CurrentValue, + propertyEntry.CurrentValue); + } + } + + protected new EntityEntry AddTestBuiltInDataTypes(DbSet set) + where TEntity : BuiltInDataTypesBase, new() + { + var entityEntry = set.Add( + new TEntity { Id = 11 }); + + entityEntry.CurrentValues.SetValues( + new BuiltInDataTypes + { + Id = 11, + PartitionId = 1, + TestInt16 = -1234, + TestInt32 = -123456789, + TestInt64 = -1234567890123456789L, + TestDouble = -1.23456789, + TestDecimal = -1234567890.01M, + TestDateTime = Fixture.DefaultDateTime, + TestDateTimeOffset = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)), + TestTimeSpan = new TimeSpan(0, 10, 9, 8, 7), + TestDateOnly = new DateOnly(2020, 3, 1), + TestTimeOnly = new TimeOnly(12, 30, 45, 0), + TestSingle = -1.234F, + TestBoolean = true, + TestByte = 255, + TestUnsignedInt16 = 1234, + TestUnsignedInt32 = 1234565789U, + TestUnsignedInt64 = 1234567890123456789UL, + TestCharacter = 'a', + TestSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + return entityEntry; + } + + public override void Can_query_using_any_nullable_data_type() + { + using var context = CreateContext(); + var source = AddTestBuiltInNullableDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInNullableDataTypesTest(source); + } + + public override void Can_query_using_any_data_type_nullable_shadow() + { + using var context = CreateContext(); + var source = AddTestBuiltInNullableDataTypes(context.Set()); + + Assert.Equal(1, context.SaveChanges()); + + QueryBuiltInNullableDataTypesTest(source); + } + + private void QueryBuiltInNullableDataTypesTest(EntityEntry source) + where TEntity : BuiltInNullableDataTypesBase + { + using var context = CreateContext(); + var set = context.Set(); + var entity = set.Where(e => e.Id == 11).ToList().Single(); + var entityType = context.Model.FindEntityType(typeof(TEntity)); + + short? param1 = -1234; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt16)) == param1) + .ToList().Single()); + + int? param2 = -123456789; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt32)) == param2) + .ToList().Single()); + + long? param3 = -1234567890123456789L; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableInt64)) == param3) + .ToList().Single()); + + double? param4 = -1.23456789; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) == param4).ToList() + .Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + double? param4l = -1.234567891; + double? param4h = -1.234567889; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) == param4 + || (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) > param4l + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDouble)) < param4h))) + .ToList().Single()); + } + + decimal? param5 = -1234567890.01M; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDecimal)) == param5) + .ToList().Single()); + + DateTime? param6 = Fixture.DefaultDateTime; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateTime)) == param6) + .ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableDateTimeOffset)) != null) + { + DateTimeOffset? param7 = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateTimeOffset)) + == param7).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableTimeSpan)) != null) + { + TimeSpan? param8 = new TimeSpan(0, 10, 9, 8, 7); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableTimeSpan)) + == param8) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableDateOnly)) != null) + { + DateOnly? param9 = new DateOnly(2020, 3, 1); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableDateOnly)) + == param9) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableTimeOnly)) != null) + { + TimeOnly? param10 = new TimeOnly(12, 30, 45, 0); + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableTimeOnly)) + == param10) + .ToList().Single()); + } + + float? param11 = -1.234F; + if (Fixture.StrictEquality) + { + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) == param11).ToList() + .Single()); + } + else if (Fixture.SupportsDecimalComparisons) + { + float? param11l = -1.2341F; + float? param11h = -1.2339F; + Assert.Same( + entity, set.Where( + e => e.Id == 11 + && (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) == param11 + || (EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) > param11l + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSingle)) < param11h))) + .ToList().Single()); + } + + bool? param12 = true; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableBoolean)) == param12) + .ToList().Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableByte)) != null) + { + byte? param13 = 255; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableByte)) == param13) + .ToList().Single()); + } + + Enum64? param14 = Enum64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == param14).ToList() + .Single()); + + Enum32? param15 = Enum32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == param15).ToList() + .Single()); + + Enum16? param16 = Enum16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == param16).ToList() + .Single()); + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum8)) != null) + { + Enum8? param17 = Enum8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == param17).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt16)) != null) + { + ushort? param18 = 1234; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt16)) + == param18).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt32)) != null) + { + uint? param19 = 1234565789U; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt32)) + == param19) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt64)) != null) + { + ulong? param20 = 1234567890123456789UL; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property( + e, nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt64)) + == param20).ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableCharacter)) != null) + { + char? param21 = 'a'; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableCharacter)) == param21) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableSignedByte)) != null) + { + sbyte? param22 = -128; + Assert.Same( + entity, + set.Where( + e => e.Id == 11 + && EF.Property(e, nameof(BuiltInNullableDataTypes.TestNullableSignedByte)) + == param22) + .ToList().Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU64)) != null) + { + var param23 = EnumU64.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU64)) == param23).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU32)) != null) + { + var param24 = EnumU32.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU32)) == param24).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU16)) != null) + { + var param25 = EnumU16.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumU16)) == param25).ToList() + .Single()); + } + + if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumS8)) != null) + { + var param26 = EnumS8.SomeValue; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.EnumS8)) == param26).ToList() + .Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum64))?.GetProviderClrType()) + == typeof(long)) + { + int? param27 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == (Enum64)param27) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum64)) == param27) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum32))?.GetProviderClrType()) + == typeof(int)) + { + int? param28 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == (Enum32)param28) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum32)) == param28) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum16))?.GetProviderClrType()) + == typeof(short)) + { + int? param29 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == (Enum16)param29) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum16)) == param29) + .ToList().Single()); + } + + if (UnwrapNullableType(entityType.FindProperty(nameof(BuiltInNullableDataTypes.Enum8))?.GetProviderClrType()) + == typeof(byte)) + { + int? param30 = 1; + Assert.Same( + entity, + set.Where(e => e.Id == 11 && EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == (Enum8)param30) + .ToList().Single()); + Assert.Same( + entity, + set.Where(e => e.Id == 11 && (int)EF.Property(e, nameof(BuiltInNullableDataTypes.Enum8)) == param30) + .ToList().Single()); + } + + foreach (var propertyEntry in context.Entry(entity).Properties) + { + if (propertyEntry.Metadata.ValueGenerated != ValueGenerated.Never) + { + continue; + } + + Assert.Equal( + source.Property(propertyEntry.Metadata).CurrentValue, + propertyEntry.CurrentValue); + } + } + + protected new virtual EntityEntry AddTestBuiltInNullableDataTypes(DbSet set) + where TEntity : BuiltInNullableDataTypesBase, new() + { + var entityEntry = set.Add( + new TEntity { Id = 11 }); + + entityEntry.CurrentValues.SetValues( + new BuiltInNullableDataTypes + { + Id = 11, + PartitionId = 1, + TestNullableInt16 = -1234, + TestNullableInt32 = -123456789, + TestNullableInt64 = -1234567890123456789L, + TestNullableDouble = -1.23456789, + TestNullableDecimal = -1234567890.01M, + TestNullableDateTime = Fixture.DefaultDateTime, + TestNullableDateTimeOffset = new DateTimeOffset(new DateTime(), TimeSpan.FromHours(-8.0)), + TestNullableTimeSpan = new TimeSpan(0, 10, 9, 8, 7), + TestNullableDateOnly = new DateOnly(2020, 3, 1), + TestNullableTimeOnly = new TimeOnly(12, 30, 45, 0), + TestNullableSingle = -1.234F, + TestNullableBoolean = true, + TestNullableByte = 255, + TestNullableUnsignedInt16 = 1234, + TestNullableUnsignedInt32 = 1234565789U, + TestNullableUnsignedInt64 = 1234567890123456789UL, + TestNullableCharacter = 'a', + TestNullableSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + return entityEntry; + } + + + + private void AssertEqualIfMapped(IEntityType entityType, T expected, Expression> actualExpression) + { + if (entityType.FindProperty(((MemberExpression)actualExpression.Body).Member.Name) != null) + { + var actual = actualExpression.Compile()(); + var type = UnwrapNullableEnumType(typeof(T)); + if (IsSignedInteger(type)) + { + Assert.True(Equal(Convert.ToInt64(expected), Convert.ToInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (IsUnsignedInteger(type)) + { + Assert.True(Equal(Convert.ToUInt64(expected), Convert.ToUInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (type == typeof(DateTime)) + { + Assert.True( + Equal((DateTime)(object)expected, (DateTime)(object)actual), $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else if (type == typeof(DateTimeOffset)) + { + Assert.True( + Equal((DateTimeOffset)(object)expected, (DateTimeOffset)(object)actual), + $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else + { + Assert.Equal(expected, actual); + } + } + } + + private bool Equal(long left, long right) + { + if (left >= 0 + && right >= 0) + { + return Equal((ulong)left, (ulong)right); + } + + if (left < 0 + && right < 0) + { + return Equal((ulong)-left, (ulong)-right); + } + + return false; + } + + private bool Equal(ulong left, ulong right) + { + if (Fixture.IntegerPrecision < 64) + { + var largestPrecise = 1ul << Fixture.IntegerPrecision; + while (left > largestPrecise) + { + left >>= 1; + right >>= 1; + } + } + + return left == right; + } + + private bool Equal(DateTime left, DateTime right) + => left.Equals(right) && (!Fixture.PreservesDateTimeKind || left.Kind == right.Kind); + + private bool Equal(DateTimeOffset left, DateTimeOffset right) + => left.EqualsExact(right); + + private static Type UnwrapNullableType(Type type) + => type == null ? null : Nullable.GetUnderlyingType(type) ?? type; + + private static bool IsSignedInteger(Type type) + => type == typeof(int) + || type == typeof(long) + || type == typeof(short) + || type == typeof(sbyte); + + private static bool IsUnsignedInteger(Type type) + => type == typeof(byte) + || type == typeof(uint) + || type == typeof(ulong) + || type == typeof(ushort) + || type == typeof(char); + public class ConvertToProviderTypesJetFixture : ConvertToProviderTypesFixtureBase { public override bool StrictEquality => true; diff --git a/test/EFCore.Jet.FunctionalTests/CustomConvertersJetTest.cs b/test/EFCore.Jet.FunctionalTests/CustomConvertersJetTest.cs index ed8a30c..4573915 100644 --- a/test/EFCore.Jet.FunctionalTests/CustomConvertersJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/CustomConvertersJetTest.cs @@ -2,9 +2,11 @@ using System; using System.Linq; +using System.Linq.Expressions; using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -224,6 +226,325 @@ User23059.MessageGroups ---> [nullable varchar] [MaxLength = 255] Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); } + public override void Can_insert_and_read_back_object_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new ObjectBackedDataTypes + { + Id = 101, + PartitionId = 101, + String = "TestString", + Bytes = new byte[] { 10, 9, 8, 7, 6 }, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(ObjectBackedDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.String); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.Bytes); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = false, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, false, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + public override void Can_insert_and_read_back_non_nullable_backed_data_types() + { + using (var context = CreateContext()) + { + context.Set().Add( + new NonNullableBackedDataTypes + { + Id = 101, + PartitionId = 101, + Int16 = -1234, + Int32 = -123456789, + Int64 = -1234567890123456789L, + Double = -1.23456789, + Decimal = -1234567890.01M, + DateTime = DateTime.Parse("01/01/2000 12:34:56"), + DateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TimeSpan = new TimeSpan(0, 10, 9, 8, 0), + DateOnly = new DateOnly(2020, 3, 1), + TimeOnly = new TimeOnly(12, 30, 45, 0), + Single = -1.234F, + Boolean = true, + Byte = 255, + UnsignedInt16 = 1234, + UnsignedInt32 = 1234565789U, + UnsignedInt64 = 1234567890123456789UL, + Character = 'a', + SignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(NonNullableBackedDataTypes)); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.Int16); + AssertEqualIfMapped(entityType, -123456789, () => dt.Int32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.Int64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.Double); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.Decimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56"), () => dt.DateTime); + AssertEqualIfMapped( + entityType, JetTestHelpers.GetExpectedValue(new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0))), + () => dt.DateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 0), () => dt.TimeSpan); + AssertEqualIfMapped(entityType, new DateOnly(2020, 3, 1), () => dt.DateOnly); + AssertEqualIfMapped(entityType, new TimeOnly(12, 30, 45, 0), () => dt.TimeOnly); + AssertEqualIfMapped(entityType, -1.234F, () => dt.Single); + AssertEqualIfMapped(entityType, true, () => dt.Boolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.Byte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.UnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.UnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.UnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.Character); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.SignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + + private void AssertEqualIfMapped(IEntityType entityType, T expected, Expression> actualExpression) + { + if (entityType.FindProperty(((MemberExpression)actualExpression.Body).Member.Name) != null) + { + var actual = actualExpression.Compile()(); + var type = UnwrapNullableEnumType(typeof(T)); + if (IsSignedInteger(type)) + { + Assert.True(Equal(Convert.ToInt64(expected), Convert.ToInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (IsUnsignedInteger(type)) + { + Assert.True(Equal(Convert.ToUInt64(expected), Convert.ToUInt64(actual)), $"Expected:\t{expected}\r\nActual:\t{actual}"); + } + else if (type == typeof(DateTime)) + { + Assert.True( + Equal((DateTime)(object)expected, (DateTime)(object)actual), $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else if (type == typeof(DateTimeOffset)) + { + Assert.True( + Equal((DateTimeOffset)(object)expected, (DateTimeOffset)(object)actual), + $"Expected:\t{expected:O}\r\nActual:\t{actual:O}"); + } + else + { + Assert.Equal(expected, actual); + } + } + } + + private bool Equal(long left, long right) + { + if (left >= 0 + && right >= 0) + { + return Equal((ulong)left, (ulong)right); + } + + if (left < 0 + && right < 0) + { + return Equal((ulong)-left, (ulong)-right); + } + + return false; + } + + private bool Equal(ulong left, ulong right) + { + if (Fixture.IntegerPrecision < 64) + { + var largestPrecise = 1ul << Fixture.IntegerPrecision; + while (left > largestPrecise) + { + left >>= 1; + right >>= 1; + } + } + + return left == right; + } + + private bool Equal(DateTime left, DateTime right) + => left.Equals(right) && (!Fixture.PreservesDateTimeKind || left.Kind == right.Kind); + + private bool Equal(DateTimeOffset left, DateTimeOffset right) + => left.EqualsExact(right); + + private static Type UnwrapNullableType(Type type) + => type == null ? null : Nullable.GetUnderlyingType(type) ?? type; + + private static bool IsSignedInteger(Type type) + => type == typeof(int) + || type == typeof(long) + || type == typeof(short) + || type == typeof(sbyte); + + private static bool IsUnsignedInteger(Type type) + => type == typeof(byte) + || type == typeof(uint) + || type == typeof(ulong) + || type == typeof(ushort) + || type == typeof(char); + public class CustomConvertersJetFixture : CustomConvertersFixtureBase { public override bool StrictEquality => true;