Skip to content

Commit 9bae654

Browse files
committed
Fix Linq .Second bug for PostgreSQL et al.
Refactor tests
1 parent 0d92dd8 commit 9bae654

File tree

6 files changed

+409
-90
lines changed

6 files changed

+409
-90
lines changed

src/NHibernate.Test/Async/Linq/DateTimeTests.cs

Lines changed: 197 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,98 +9,252 @@
99

1010

1111
using System;
12+
using System.Data;
1213
using System.Linq;
14+
using NHibernate.Cfg;
15+
using NHibernate.SqlTypes;
16+
using NHibernate.Mapping.ByCode;
1317
using NUnit.Framework;
18+
using NHibernate.Type;
1419
using NHibernate.Linq;
20+
using System.Linq.Expressions;
1521

1622
namespace NHibernate.Test.Linq
1723
{
1824
using System.Threading.Tasks;
25+
using System.Threading;
1926
[TestFixture]
20-
public class DateTimeTestsAsync : LinqTestCase
27+
public class DateTimeTestsAsync : TestCase
2128
{
29+
private bool DialectSupportsDateTimeOffset => TestDialect.SupportsSqlType(new SqlType(DbType.DateTimeOffset));
30+
private bool DialectSupportsDateTimeWithScale => TestDialect.SupportsSqlType(new SqlType(DbType.DateTime, 2));
31+
32+
private DateTimeTestsClass[] _referenceEntities = new DateTimeTestsClass[]
33+
{
34+
new() {Id =1, DateTimeValue = new DateTime(1998, 02, 26)},
35+
new() {Id =2, DateTimeValue = new DateTime(1998, 02, 26)},
36+
new() {Id =3, DateTimeValue = new DateTime(1998, 02, 26, 01, 01, 01)},
37+
new() {Id =4, DateTimeValue = new DateTime(1998, 02, 26, 02, 02, 02)},
38+
new() {Id =5, DateTimeValue = new DateTime(1998, 02, 26, 03, 03, 03)},
39+
new() {Id =6, DateTimeValue = new DateTime(1998, 02, 26, 04, 04, 04)},
40+
new() {Id =7, DateTimeValue = new DateTime(1998, 03, 01)},
41+
new() {Id =8, DateTimeValue = new DateTime(2000, 01, 01)}
42+
};
43+
44+
protected override string[] Mappings => default;
45+
protected override void AddMappings(Configuration configuration)
46+
{
47+
var modelMapper = new ModelMapper();
48+
49+
modelMapper.Class<DateTimeTestsClass>(m =>
50+
{
51+
m.Table("datetimetests");
52+
m.Lazy(false);
53+
m.Id(p => p.Id, p => p.Generator(Generators.Assigned));
54+
m.Property(p => p.DateValue, c => c.Type<DateType>());
55+
m.Property(p => p.DateTimeValue);
56+
m.Property(p => p.DateTimeValueWithScale, c => c.Scale(2));
57+
if (DialectSupportsDateTimeOffset)
58+
{
59+
m.Property(p => p.DateTimeOffsetValue);
60+
m.Property(p => p.DateTimeOffsetValueWithScale, c => c.Scale(2));
61+
}
62+
});
63+
var mapping = modelMapper.CompileMappingForAllExplicitlyAddedEntities();
64+
configuration.AddMapping(mapping);
65+
}
66+
67+
protected override void OnSetUp()
68+
{
69+
foreach (var entity in _referenceEntities)
70+
{
71+
entity.DateValue = entity.DateTimeValue.Date;
72+
entity.DateTimeValueWithScale = entity.DateTimeValue.AddSeconds(0.9);
73+
entity.DateTimeOffsetValue = new DateTimeOffset(entity.DateTimeValue, TimeSpan.FromHours(3));
74+
entity.DateTimeOffsetValueWithScale = new DateTimeOffset(entity.DateTimeValue, TimeSpan.FromHours(3));
75+
}
76+
77+
using (var session = OpenSession())
78+
using (var trans = session.BeginTransaction())
79+
{
80+
foreach (var entity in _referenceEntities)
81+
{
82+
session.Save(entity);
83+
}
84+
trans.Commit();
85+
}
86+
}
87+
88+
protected override void OnTearDown()
89+
{
90+
using (var session = OpenSession())
91+
using (var trans = session.BeginTransaction())
92+
{
93+
session.Query<DateTimeTestsClass>().Delete();
94+
trans.Commit();
95+
}
96+
}
97+
98+
private void AssertDateTimeOffsetSupported()
99+
{
100+
if (!DialectSupportsDateTimeOffset)
101+
{
102+
Assert.Ignore("Dialect doesn't support DateTimeOffset");
103+
}
104+
}
105+
106+
private void AssertDateTimeWithScaleSupported()
107+
{
108+
if (!DialectSupportsDateTimeWithScale)
109+
{
110+
Assert.Ignore("Dialect doesn't support DateTime with scale (2)");
111+
}
112+
}
113+
114+
private Task AssertQueryAsync(Expression<Func<DateTimeTestsClass, bool>> where, CancellationToken cancellationToken = default(CancellationToken)) => AssertQueryAsync(where, x => x.Id, cancellationToken);
115+
116+
private async Task AssertQueryAsync<TSelect>(Expression<Func<DateTimeTestsClass, bool>> where, Expression<Func<DateTimeTestsClass, TSelect>> select, CancellationToken cancellationToken = default(CancellationToken))
117+
{
118+
using var session = OpenSession();
119+
var fromDb = await (session.Query<DateTimeTestsClass>().Where(where).Select(select).ToListAsync(cancellationToken));
120+
var fromMemory = _referenceEntities.AsQueryable().Where(where).Select(select).AsEnumerable().ToList(); //AsEnumerable added to avoid async generator
121+
Assert.That(fromMemory, Has.Count.GreaterThan(0), "Inconclusive, since the query doesn't match anything in the defined set");
122+
Assert.That(fromDb, Has.Count.EqualTo(fromMemory.Count));
123+
Assert.That(fromDb, Is.EquivalentTo(fromMemory));
124+
}
125+
22126
[Test]
23127
public async Task CanQueryByYearAsync()
24128
{
25-
var x = await ((from o in db.Orders
26-
where o.OrderDate.Value.Year == 1998
27-
select o).ToListAsync());
129+
await (AssertQueryAsync(o => o.DateTimeValue.Year == 1998));
130+
}
28131

29-
Assert.AreEqual(270, x.Count());
132+
[Test]
133+
public async Task CanQueryDateTimeBySecondAsync()
134+
{
135+
await (AssertQueryAsync(o => o.DateTimeValue.Second == 4));
30136
}
31137

32138
[Test]
33-
public async Task CanQueryByDateAsync()
139+
public async Task CanQueryDateTimeByMinuteAsync()
34140
{
35-
var x = await ((from o in db.Orders
36-
where o.OrderDate.Value.Date == new DateTime(1998, 02, 26)
37-
select o).ToListAsync());
141+
await (AssertQueryAsync(o => o.DateTimeValue.Minute == 4));
142+
}
38143

39-
Assert.AreEqual(6, x.Count());
144+
[Test]
145+
public async Task CanQueryDateTimeByHourAsync()
146+
{
147+
await (AssertQueryAsync(o => o.DateTimeValue.Hour == 4));
40148
}
41149

42150
[Test]
43-
public async Task CanQueryByDateTimeAsync()
151+
public async Task CanQueryDateTimeBySecondWhenValueContainsFractionalSecondsAsync()
152+
{
153+
AssertDateTimeWithScaleSupported();
154+
await (AssertQueryAsync(o => o.DateTimeValueWithScale.Second == 4));
155+
}
156+
157+
[Test]
158+
public async Task CanQueryDateTimeOffsetBySecondAsync()
44159
{
45-
var x = await ((from o in db.Orders
46-
where o.OrderDate.Value == new DateTime(1998, 02, 26)
47-
select o).ToListAsync());
160+
AssertDateTimeOffsetSupported();
161+
await (AssertQueryAsync(o => o.DateTimeOffsetValue.Second == 4));
162+
}
48163

49-
Assert.AreEqual(5, x.Count());
164+
[Test]
165+
public async Task CanQueryDateTimeOffsetByMinuteAsync()
166+
{
167+
AssertDateTimeOffsetSupported();
168+
await (AssertQueryAsync(o => o.DateTimeOffsetValue.Minute == 4));
50169
}
51170

52171
[Test]
53-
public async Task CanQueryByDateTime2Async()
172+
public async Task CanQueryDateTimeOffsetByHourAsync()
54173
{
55-
var x = await ((from o in db.Orders
56-
where o.OrderDate.Value == new DateTime(1998, 02, 26, 0, 1, 0)
57-
select o).ToListAsync());
174+
AssertDateTimeOffsetSupported();
175+
await (AssertQueryAsync(o => o.DateTimeOffsetValue.Hour == 4));
176+
}
58177

59-
Assert.AreEqual(1, x.Count());
178+
[Test]
179+
public async Task CanQueryDateTimeOffsetBySecondWhenValueContainsFractionalSecondsAsync()
180+
{
181+
AssertDateTimeOffsetSupported();
182+
await (AssertQueryAsync(o => o.DateTimeOffsetValueWithScale.Second == 4));
60183
}
61184

62185
[Test]
63-
public async Task CanSelectYearAsync()
186+
public async Task CanQueryByDateAsync()
64187
{
65-
var x = await ((from o in db.Orders
66-
where o.OrderDate.Value.Year == 1998
67-
select o.OrderDate.Value.Year).ToListAsync());
188+
await (AssertQueryAsync(o => o.DateTimeValue.Date == new DateTime(1998, 02, 26)));
189+
}
68190

69-
Assert.That(x, Has.All.EqualTo(1998));
70-
Assert.AreEqual(270, x.Count());
191+
[Test]
192+
public async Task CanQueryByDateTimeAsync()
193+
{
194+
await (AssertQueryAsync(o => o.DateTimeValue == new DateTime(1998, 02, 26)));
71195
}
72196

73197
[Test]
74-
public async Task CanSelectDateAsync()
198+
public async Task CanQueryByDateTime2Async()
75199
{
76-
var x = await ((from o in db.Orders
77-
where o.OrderDate.Value.Date == new DateTime(1998, 02, 26)
78-
select o.OrderDate.Value.Date).ToListAsync());
200+
await (AssertQueryAsync(o => o.DateTimeValue == new DateTime(1998, 02, 26, 1, 1, 1)));
201+
}
79202

80-
Assert.That(x, Has.All.EqualTo(new DateTime(1998, 02, 26)));
81-
Assert.AreEqual(6, x.Count());
203+
[Test]
204+
public async Task CanSelectYearAsync()
205+
{
206+
await (AssertQueryAsync(o => o.DateTimeValue.Year == 1998, o => o.DateTimeValue.Year));
82207
}
83208

84209
[Test]
85-
public async Task CanSelectDateTimeAsync()
210+
public async Task CanSelectDateAsync()
86211
{
87-
var x = await ((from o in db.Orders
88-
where o.OrderDate.Value == new DateTime(1998, 02, 26)
89-
select o.OrderDate.Value).ToListAsync());
212+
await (AssertQueryAsync(o => o.DateTimeValue.Date == new DateTime(1998, 02, 26), o => o.DateTimeValue.Date));
213+
}
90214

91-
Assert.That(x, Has.All.EqualTo(new DateTime(1998, 02, 26)));
92-
Assert.AreEqual(5, x.Count());
215+
[Test]
216+
public async Task CanSelectDateTimeAsync()
217+
{
218+
await (AssertQueryAsync(o => o.DateTimeValue == new DateTime(1998, 02, 26), o => o.DateTimeValue));
93219
}
94220

95221
[Test]
96222
public async Task CanSelectDateTime2Async()
97223
{
98-
var x = await ((from o in db.Orders
99-
where o.OrderDate.Value == new DateTime(1998, 02, 26, 0, 1, 0)
100-
select o.OrderDate.Value).ToListAsync());
224+
await (AssertQueryAsync(o => o.DateTimeValue == new DateTime(1998, 02, 26, 1, 1, 1), o => o.DateTimeValue));
225+
}
226+
227+
[Test]
228+
public async Task CanSelectDateTimeWithScaleAsync()
229+
{
230+
AssertDateTimeWithScaleSupported();
231+
await (AssertQueryAsync(o => o.DateTimeValueWithScale == _referenceEntities[0].DateTimeValueWithScale, o => o.DateTimeValueWithScale));
232+
}
233+
234+
public class DateTimeTestsClass : IEquatable<DateTimeTestsClass>
235+
{
236+
public int Id { get; set; }
237+
public DateTime DateTimeValue { get; set; }
238+
public DateTime DateTimeValueWithScale { get; set; }
239+
public DateTimeOffset DateTimeOffsetValue { get; set; }
240+
public DateTimeOffset DateTimeOffsetValueWithScale { get; set; }
241+
public DateTime DateValue { get; set; }
242+
243+
public override bool Equals(object obj)
244+
{
245+
return Equals(obj as DateTimeTestsClass);
246+
}
247+
248+
public bool Equals(DateTimeTestsClass other)
249+
{
250+
return other is not null &&
251+
Id.Equals(other.Id);
252+
}
101253

102-
Assert.That(x, Has.All.EqualTo(new DateTime(1998, 02, 26, 0, 1, 0)));
103-
Assert.AreEqual(1, x.Count());
254+
public override int GetHashCode()
255+
{
256+
return HashCode.Combine(Id);
257+
}
104258
}
105259
}
106260
}

0 commit comments

Comments
 (0)