Skip to content

Commit 72aaccb

Browse files
fredericDelaportehazzik
authored andcommitted
NH-3919 - More datetime tests and refactor them.
1 parent 3be6668 commit 72aaccb

27 files changed

+1349
-870
lines changed
Lines changed: 392 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,392 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Collections.Generic;
13+
using System.Data;
14+
using System.Data.Common;
15+
using System.Linq;
16+
using System.Reflection;
17+
using NHibernate.Cfg;
18+
using NHibernate.Driver;
19+
using NHibernate.Engine;
20+
using NHibernate.SqlCommand;
21+
using NHibernate.SqlTypes;
22+
using NHibernate.Tool.hbm2ddl;
23+
using NHibernate.Type;
24+
using NHibernate.Util;
25+
using NUnit.Framework;
26+
27+
namespace NHibernate.Test.TypesTest
28+
{
29+
using System.Threading.Tasks;
30+
using System.Threading;
31+
[TestFixture]
32+
public abstract class AbstractDateTimeTypeFixtureAsync : TypeFixtureBase
33+
{
34+
protected abstract AbstractDateTimeType Type { get; }
35+
protected virtual bool RevisionCheck => true;
36+
37+
protected const int DateId = 1;
38+
protected const int AdditionalDateId = 2;
39+
40+
protected override void Configure(Configuration configuration)
41+
{
42+
base.Configure(configuration);
43+
44+
var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver));
45+
ClientDriverWithParamsStats.DriverClass = driverClass;
46+
47+
configuration.SetProperty(
48+
Cfg.Environment.ConnectionDriver,
49+
typeof(ClientDriverWithParamsStats).AssemblyQualifiedName);
50+
}
51+
52+
protected override void OnSetUp()
53+
{
54+
base.OnSetUp();
55+
56+
using (var s = OpenSession())
57+
using (var t = s.BeginTransaction())
58+
{
59+
var d = new DateTimeClass
60+
{
61+
Id = DateId,
62+
Value = Now
63+
};
64+
s.Save(d);
65+
t.Commit();
66+
}
67+
}
68+
69+
protected override void OnTearDown()
70+
{
71+
base.OnTearDown();
72+
73+
using (var s = OpenSession())
74+
using (var t = s.BeginTransaction())
75+
{
76+
s.CreateQuery("delete from DateTimeClass").ExecuteUpdate();
77+
t.Commit();
78+
}
79+
}
80+
81+
protected override void DropSchema()
82+
{
83+
(Sfi.ConnectionProvider.Driver as ClientDriverWithParamsStats)?.CleanUp();
84+
base.DropSchema();
85+
}
86+
87+
[Test]
88+
public async Task NextAsync()
89+
{
90+
var current = DateTime.Parse("2004-01-01");
91+
var next = await (Type.NextAsync(current, null, CancellationToken.None));
92+
93+
Assert.That(next, Is.TypeOf<DateTime>(), "next should be DateTime");
94+
Assert.That(next, Is.GreaterThan(current), "next should be greater than current");
95+
}
96+
97+
[Test]
98+
public async Task SeedAsync()
99+
{
100+
Assert.That(await (Type.SeedAsync(null, CancellationToken.None)), Is.TypeOf<DateTime>(), "seed should be DateTime");
101+
}
102+
103+
[Test]
104+
[TestCase(DateTimeKind.Unspecified)]
105+
[TestCase(DateTimeKind.Local)]
106+
[TestCase(DateTimeKind.Utc)]
107+
public virtual async Task ReadWriteAsync(DateTimeKind kind)
108+
{
109+
var entity = new DateTimeClass
110+
{
111+
Id = AdditionalDateId,
112+
Value = GetTestDate(kind)
113+
};
114+
115+
// Now must be acquired before transaction because some db freezes current_timestamp at transaction start,
116+
// like PostgreSQL. https://www.postgresql.org/docs/7.2/static/functions-datetime.html#AEN6700
117+
// This then wrecks tests with DbTimestampType if the always out of tran Now is called for fetching
118+
// beforeNow only after transaction start.
119+
// And account db accuracy
120+
var beforeNow = Now.AddTicks(-DateAccuracyInTicks);
121+
// Save
122+
using (var s = OpenSession())
123+
using (var t = s.BeginTransaction())
124+
{
125+
await (s.SaveAsync(entity));
126+
await (t.CommitAsync());
127+
}
128+
var afterNow = Now.AddTicks(DateAccuracyInTicks);
129+
130+
var typeKind = GetTypeKind();
131+
if (RevisionCheck)
132+
{
133+
Assert.That(entity.Revision, Is.GreaterThan(beforeNow).And.LessThan(afterNow), "Revision not correctly seeded.");
134+
if (typeKind != DateTimeKind.Unspecified)
135+
Assert.That(entity.Revision.Kind, Is.EqualTo(typeKind), "Revision kind not correctly seeded.");
136+
Assert.That(entity.NullableValue, Is.Null, "NullableValue unexpectedly seeded.");
137+
}
138+
139+
// Retrieve, compare then update
140+
DateTimeClass retrieved;
141+
using (var s = OpenSession())
142+
{
143+
using (var t = s.BeginTransaction())
144+
{
145+
retrieved = await (s.GetAsync<DateTimeClass>(AdditionalDateId));
146+
147+
Assert.That(retrieved, Is.Not.Null, "Entity not saved or cannot be retrieved by its key.");
148+
Assert.That(retrieved.Value, Is.EqualTo(entity.Value), "Value should be the same.");
149+
if (RevisionCheck)
150+
Assert.That(retrieved.Revision, Is.EqualTo(entity.Revision), "Revision should be the same.");
151+
Assert.That(retrieved.NullableValue, Is.EqualTo(entity.NullableValue), "NullableValue should be the same.");
152+
if (typeKind != DateTimeKind.Unspecified)
153+
{
154+
Assert.That(retrieved.Value.Kind, Is.EqualTo(typeKind), "Value kind not correctly retrieved.");
155+
if (RevisionCheck)
156+
Assert.That(retrieved.Revision.Kind, Is.EqualTo(typeKind), "Revision kind not correctly retrieved.");
157+
}
158+
await (t.CommitAsync());
159+
}
160+
beforeNow = Now.AddTicks(-DateAccuracyInTicks);
161+
using (var t = s.BeginTransaction())
162+
{
163+
retrieved.NullableValue = GetTestDate(kind);
164+
retrieved.Value = GetTestDate(kind).AddMonths(-1);
165+
await (t.CommitAsync());
166+
}
167+
afterNow = Now.AddTicks(DateAccuracyInTicks);
168+
}
169+
170+
if (RevisionCheck)
171+
{
172+
Assert.That(
173+
retrieved.Revision,
174+
Is.GreaterThan(beforeNow).And.LessThan(afterNow).And.GreaterThanOrEqualTo(entity.Revision),
175+
"Revision not correctly incremented.");
176+
if (typeKind != DateTimeKind.Unspecified)
177+
Assert.That(retrieved.Revision.Kind, Is.EqualTo(typeKind), "Revision kind incorrectly changed.");
178+
}
179+
180+
// Retrieve and compare again
181+
using (var s = OpenSession())
182+
using (var t = s.BeginTransaction())
183+
{
184+
var retrievedAgain = await (s.GetAsync<DateTimeClass>(AdditionalDateId));
185+
186+
Assert.That(retrievedAgain, Is.Not.Null, "Entity deleted or cannot be retrieved again by its key.");
187+
Assert.That(retrievedAgain.Value, Is.EqualTo(retrieved.Value), "Value should be the same again.");
188+
if (RevisionCheck)
189+
Assert.That(retrievedAgain.Revision, Is.EqualTo(retrieved.Revision), "Revision should be the same again.");
190+
Assert.That(
191+
retrievedAgain.NullableValue,
192+
Is.EqualTo(retrieved.NullableValue),
193+
"NullableValue should be the same again.");
194+
if (typeKind != DateTimeKind.Unspecified)
195+
{
196+
Assert.That(retrievedAgain.Value.Kind, Is.EqualTo(typeKind), "Value kind not correctly retrieved again.");
197+
if (RevisionCheck)
198+
Assert.That(retrievedAgain.Revision.Kind, Is.EqualTo(typeKind), "Revision kind not correctly retrieved again.");
199+
Assert.That(
200+
retrievedAgain.NullableValue.Value.Kind,
201+
Is.EqualTo(typeKind),
202+
"NullableValue kind not correctly retrieved again.");
203+
}
204+
await (t.CommitAsync());
205+
}
206+
}
207+
208+
[Test]
209+
public Task DbHasExpectedTypeAsync()
210+
{
211+
try
212+
{
213+
var validator = new SchemaValidator(cfg);
214+
return validator.ValidateAsync();
215+
}
216+
catch (Exception ex)
217+
{
218+
return Task.FromException<object>(ex);
219+
}
220+
}
221+
222+
[Test]
223+
public virtual async Task SaveUseExpectedSqlTypeAsync()
224+
{
225+
var driver = (ClientDriverWithParamsStats) Sfi.ConnectionProvider.Driver;
226+
227+
using (var s = OpenSession())
228+
using (var t = s.BeginTransaction())
229+
{
230+
var d = new DateTimeClass
231+
{
232+
Id = 2,
233+
Value = Now,
234+
NullableValue = Now
235+
};
236+
driver.ClearStats();
237+
await (s.SaveAsync(d));
238+
await (t.CommitAsync());
239+
}
240+
241+
// 2 properties + revision
242+
AssertSqlType(driver, 3);
243+
}
244+
245+
[Test]
246+
public virtual async Task UpdateUseExpectedSqlTypeAsync()
247+
{
248+
var driver = (ClientDriverWithParamsStats) Sfi.ConnectionProvider.Driver;
249+
250+
using (var s = OpenSession())
251+
using (var t = s.BeginTransaction())
252+
{
253+
var d = await (s.GetAsync<DateTimeClass>(DateId));
254+
d.Value = Now;
255+
d.NullableValue = Now;
256+
driver.ClearStats();
257+
await (t.CommitAsync());
258+
}
259+
260+
// 2 properties + revision x 2 (check + update)
261+
AssertSqlType(driver, 4);
262+
}
263+
264+
[Test]
265+
public virtual async Task QueryUseExpectedSqlTypeAsync()
266+
{
267+
if (!TestDialect.SupportsNonDataBoundCondition)
268+
Assert.Ignore("Dialect does not support the test query");
269+
270+
var driver = (ClientDriverWithParamsStats) Sfi.ConnectionProvider.Driver;
271+
272+
using (var s = OpenSession())
273+
using (var t = s.BeginTransaction())
274+
{
275+
var q = s
276+
.CreateQuery(
277+
"from DateTimeClass d where d.Value = :value and " +
278+
"d.NullableValue = :nullableValue and " +
279+
"d.Revision = :revision and " +
280+
":other1 = :other2")
281+
.SetDateTime("value", Now)
282+
.SetDateTime("nullableValue", Now)
283+
.SetDateTime("revision", Now)
284+
.SetDateTime("other1", Now)
285+
.SetDateTime("other2", Now);
286+
driver.ClearStats();
287+
await (q.ListAsync<DateTimeClass>());
288+
await (t.CommitAsync());
289+
}
290+
291+
AssertSqlType(driver, 5);
292+
}
293+
294+
private void AssertSqlType(ClientDriverWithParamsStats driver, int expectedCount)
295+
{
296+
if (Type.SqlTypes(Sfi).Any(t => Equals(t, SqlTypeFactory.DateTime2)))
297+
{
298+
Assert.That(
299+
driver.GetCount(SqlTypeFactory.DateTime),
300+
Is.EqualTo(0),
301+
"Found unexpected SqlTypeFactory.DateTime usages.");
302+
Assert.That(
303+
driver.GetCount(SqlTypeFactory.DateTime2),
304+
Is.EqualTo(expectedCount),
305+
"Unexpected SqlTypeFactory.DateTime2 usage count.");
306+
Assert.That(driver.GetCount(DbType.DateTime), Is.EqualTo(0), "Found unexpected DbType.DateTime usages.");
307+
Assert.That(
308+
driver.GetCount(DbType.DateTime2),
309+
Is.EqualTo(expectedCount),
310+
"Unexpected DbType.DateTime2 usage count.");
311+
}
312+
else if (Type.SqlTypes(Sfi).Any(t => Equals(t, SqlTypeFactory.DateTime)))
313+
{
314+
Assert.That(
315+
driver.GetCount(SqlTypeFactory.DateTime2),
316+
Is.EqualTo(0),
317+
"Found unexpected SqlTypeFactory.DateTime2 usages.");
318+
Assert.That(
319+
driver.GetCount(SqlTypeFactory.DateTime),
320+
Is.EqualTo(expectedCount),
321+
"Unexpected SqlTypeFactory.DateTime usage count.");
322+
Assert.That(driver.GetCount(DbType.DateTime2), Is.EqualTo(0), "Found unexpected DbType.DateTime2 usages.");
323+
Assert.That(driver.GetCount(DbType.DateTime), Is.EqualTo(expectedCount), "Unexpected DbType.DateTime usage count.");
324+
}
325+
else if (Type.SqlTypes(Sfi).Any(t => Equals(t, SqlTypeFactory.Date)))
326+
{
327+
Assert.That(
328+
driver.GetCount(SqlTypeFactory.DateTime),
329+
Is.EqualTo(0),
330+
"Found unexpected SqlTypeFactory.DateTime usages.");
331+
Assert.That(
332+
driver.GetCount(SqlTypeFactory.Date),
333+
Is.EqualTo(expectedCount),
334+
"Unexpected SqlTypeFactory.Date usage count.");
335+
Assert.That(driver.GetCount(DbType.DateTime), Is.EqualTo(0), "Found unexpected DbType.DateTime usages.");
336+
Assert.That(driver.GetCount(DbType.Date), Is.EqualTo(expectedCount), "Unexpected DbType.Date usage count.");
337+
}
338+
}
339+
340+
protected virtual long DateAccuracyInTicks => Dialect.TimestampResolutionInTicks;
341+
342+
protected virtual DateTime Now => GetTypeKind() == DateTimeKind.Utc ? DateTime.UtcNow : DateTime.Now;
343+
344+
protected virtual DateTime GetTestDate(DateTimeKind kind)
345+
{
346+
return AbstractDateTimeType.Round(
347+
kind == DateTimeKind.Utc ? DateTime.UtcNow : DateTime.SpecifyKind(DateTime.Now, kind),
348+
DateAccuracyInTicks)
349+
// Take another date than now for checking the value do not get overridden by seeding.
350+
.AddDays(1);
351+
}
352+
353+
/// <summary>
354+
/// Return a date time still considered equal but as different as possible.
355+
/// </summary>
356+
/// <param name="original">The originale date time.</param>
357+
/// <returns>An equal date time.</returns>
358+
protected virtual DateTime GetSameDate(DateTime original)
359+
{
360+
if (GetTypeKind() != DateTimeKind.Unspecified)
361+
return new DateTime(original.Ticks, original.Kind);
362+
363+
switch (original.Kind)
364+
{
365+
case DateTimeKind.Local:
366+
return DateTime.SpecifyKind(original, DateTimeKind.Unspecified);
367+
case DateTimeKind.Unspecified:
368+
return DateTime.SpecifyKind(original, DateTimeKind.Utc);
369+
default:
370+
return DateTime.SpecifyKind(original, DateTimeKind.Local);
371+
}
372+
}
373+
374+
/// <summary>
375+
/// Return a different date time but as few different as possible.
376+
/// </summary>
377+
/// <param name="original">The originale date time.</param>
378+
/// <returns>An inequal date time.</returns>
379+
protected virtual DateTime GetDifferentDate(DateTime original)
380+
{
381+
return original.AddTicks(DateAccuracyInTicks);
382+
}
383+
384+
private static readonly PropertyInfo _kindProperty =
385+
typeof(AbstractDateTimeType).GetProperty("Kind", BindingFlags.Instance | BindingFlags.NonPublic);
386+
387+
protected DateTimeKind GetTypeKind()
388+
{
389+
return (DateTimeKind) _kindProperty.GetValue(Type);
390+
}
391+
}
392+
}

0 commit comments

Comments
 (0)