Skip to content

Commit a5e7761

Browse files
authored
Merge pull request #480 from njlr/enhancement/issue-426-date-time-kinds
Adds parameter for `DateTimeKind`
2 parents 6ebc0c9 + 0797aa9 commit a5e7761

6 files changed

Lines changed: 51 additions & 46 deletions

File tree

src/Hedgehog.NUnit/GenAttribute.Prelude.fs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ type DateTimeAttribute(kind: DateTimeKind, from: DateTime, duration: TimeSpan) =
142142
new(from, duration) = DateTimeAttribute(DateTimeKind.Utc, from, duration)
143143
new(kind) = DateTimeAttribute(kind, DateTime(2000, 1, 1), TimeSpan.FromDays(3650))
144144
override _.Generator =
145-
Gen.dateTime (Range.constant from (from + duration))
146-
|> Gen.map (fun x -> DateTime.SpecifyKind(x, kind))
145+
Gen.dateTime (Range.constant from (from + duration)) (Gen.constant kind)
147146

148147
/// Generates a DateTimeOffset value.
149148
type DateTimeOffsetAttribute(from: DateTimeOffset, duration: TimeSpan) =

src/Hedgehog.Xunit/GenAttribute.Prelude.fs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,7 @@ type DateTimeAttribute(kind: DateTimeKind, from: DateTime, duration: TimeSpan) =
141141
new(from, duration) = DateTimeAttribute(DateTimeKind.Utc, from, duration)
142142
new(kind) = DateTimeAttribute(kind, DateTime(2000, 1, 1), TimeSpan.FromDays(3650))
143143
override _.Generator =
144-
Gen.dateTime (Range.constant from (from + duration))
145-
|> Gen.map (fun x -> DateTime.SpecifyKind(x, kind))
144+
Gen.dateTime (Range.constant from (from + duration)) (Gen.constant kind)
146145

147146
/// Generates a DateTimeOffset value.
148147
type DateTimeOffsetAttribute(from: DateTimeOffset, duration: TimeSpan) =

src/Hedgehog/Autogen/DefaultGenerators.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type DefaultGenerators =
3333
DateTime.MinValue.Ticks
3434
DateTime.MaxValue.Ticks
3535
|> Range.map DateTime
36-
Gen.dateTime dateTimeRange |> Gen.map DateTimeOffset
36+
Gen.dateTime dateTimeRange (Gen.constant DateTimeKind.Unspecified) |> Gen.map DateTimeOffset
3737

3838
static member ImmutableList<'a>(context: AutoGenContext, valueGen: Gen<'a>) : Gen<ImmutableList<'a>> =
3939
if context.CanRecurse then

src/Hedgehog/Gen.DateTime.fs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@ module GenDateTime =
1111
module Gen =
1212

1313
/// <summary>
14-
/// Generates a random DateTime using the given range.
14+
/// Generates a random DateTimeKind uniformly.
15+
/// </summary>
16+
let dateTimeKind : Gen<DateTimeKind> =
17+
Gen.item
18+
[|
19+
DateTimeKind.Utc
20+
DateTimeKind.Local
21+
DateTimeKind.Unspecified
22+
|]
23+
24+
/// <summary>
25+
/// Generates a random DateTime using the given range and `DateTimeKind` generator.
1526
/// </summary>
1627
/// <example>
1728
/// <code>
@@ -22,12 +33,26 @@ module GenDateTime =
2233
/// </code>
2334
/// </example>
2435
/// <param name="range">Range determining the bounds of the <c>DateTime</c> that can be generated.</param>
25-
let dateTime (range : Range<DateTime>) : Gen<DateTime> =
36+
/// <param name="kind">Generator determining the <c>DateTimeKind</c>.</param>
37+
let dateTime (range : Range<DateTime>) (kind : Gen<DateTimeKind>) : Gen<DateTime> =
2638
gen {
2739
let! ticks = range |> Range.map _.Ticks |> Gen.integral
28-
return DateTime ticks
40+
and! kind = kind
41+
return DateTime(ticks, kind)
2942
}
3043

44+
/// Generates a DateTime using the given range with UTC kind.
45+
let dateTimeUtc (range : Range<DateTime>) : Gen<DateTime> =
46+
dateTime range (Gen.constant DateTimeKind.Utc)
47+
48+
/// Generates a DateTime using the given range with Local kind.
49+
let dateTimeLocal (range : Range<DateTime>) : Gen<DateTime> =
50+
dateTime range (Gen.constant DateTimeKind.Local)
51+
52+
/// Generates a DateTime using the given range with Unspecified kind.
53+
let dateTimeUnspecified (range : Range<DateTime>) : Gen<DateTime> =
54+
dateTime range (Gen.constant DateTimeKind.Unspecified)
55+
3156
/// Generates a random DateTimeOffset using the given range.
3257
let dateTimeOffset (range : Range<DateTimeOffset>) : Gen<DateTimeOffset> =
3358
gen {

src/Hedgehog/Linq/Gen.fs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,10 @@ type Gen private () =
299299
/// </code>
300300
/// </example>
301301
/// <param name="range">Range determining the bounds of the <c>DateTime</c> that can be generated.</param>
302-
static member DateTime (range : Range<DateTime>) : Gen<DateTime> =
303-
Gen.dateTime range
302+
/// <param name="kind">Generator for the <c>DateTimeKind</c> that can be generated.</param>
303+
static member DateTime (range : Range<DateTime>, ?kind) : Gen<DateTime> =
304+
let kind = defaultArg kind (Gen.constant DateTimeKind.Unspecified)
305+
Gen.dateTime range kind
304306

305307
/// Generates a random DateTimeOffset using the given range.
306308
static member DateTimeOffset (range : Range<DateTimeOffset>) : Gen<DateTimeOffset> =

tests/Hedgehog.Tests/GenTests.fs

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,17 @@ let genTests = testList "Gen tests" [
5656
[ 8; 16; 32; 64; 128; 256; 512 ] <| fun count ->
5757

5858
let actual =
59-
(Range.constant DateTime.MinValue DateTime.MaxValue)
60-
|> Gen.dateTime
59+
Gen.dateTime
60+
(Range.constant DateTime.MinValue DateTime.MaxValue)
61+
(Gen.constant DateTimeKind.Unspecified)
6162
|> Gen.sample 0 count
6263
|> Seq.toList
6364

6465
actual
6566
|> List.distinct
6667
|> List.length
6768
=! actual.Length
68-
69+
6970
#if !FABLE_COMPILER
7071
// See production code
7172
yield! testCases "timeSpan creates TimeSpan instances"
@@ -97,45 +98,24 @@ let genTests = testList "Gen tests" [
9798
|> Seq.toList
9899
[] =! List.filter (fun ch -> ch = char nonchar) actual
99100

100-
testCase "dateTime randomly generates value between max and min ticks" <| fun _ ->
101-
// This is a bad test because essentially the same logic used to
102-
// implement Gen.dateTime appears in this test. However, keeping it for
103-
// now.
104-
let seed = Seed.random ()
105-
let range =
106-
Range.constant
107-
DateTime.MinValue.Ticks
108-
DateTime.MaxValue.Ticks
109-
let ticks =
110-
Random.integral range
111-
|> Random.run seed 0
112-
113-
let actual =
114-
Range.constant DateTime.MinValue DateTime.MaxValue
115-
|> Gen.dateTime
116-
|> Gen.toRandom
117-
|> Random.run seed 0
118-
|> Tree.outcome
119-
120-
let expected = DateTime ticks
121-
actual =! expected
122-
123101
testCase "dateTime shrinks to correct mid-value" <| fun _ ->
124102
let generatedValues =
125103
property {
126104
let! actual =
127-
(Range.constantFrom
128-
(DateTime (2000, 1, 1))
129-
DateTime.MinValue
130-
DateTime.MaxValue)
131-
|> Gen.dateTime
105+
Gen.dateTime
106+
(Range.constantFrom
107+
(DateTime (2000, 1, 1))
108+
DateTime.MinValue
109+
DateTime.MaxValue)
110+
(Gen.constant DateTimeKind.Unspecified)
111+
132112
actual =! DateTime.Now
133113
}
134114
|> expectFailureWithGeneratedValues
135115

136116
if List.isEmpty generatedValues then
137117
failwith "Should have generated values in journal"
138-
118+
139119
let actual = generatedValues.[0] :?> DateTime
140120
actual =! DateTime (2000, 1, 1)
141121

@@ -337,20 +317,20 @@ let genTests = testList "Gen tests" [
337317
let firstValues = System.Collections.Generic.HashSet<int>()
338318
let secondValues = System.Collections.Generic.HashSet<int>()
339319
let thirdValues = System.Collections.Generic.HashSet<int>()
340-
320+
341321
property {
342322
let! x = Gen.int32 (Range.linear 1 100)
343323
let! y = Gen.int32 (Range.linear 1 100)
344324
let! z = Gen.int32 (Range.linear 1 100)
345-
325+
346326
firstValues.Add(x) |> ignore
347327
secondValues.Add(y) |> ignore
348328
thirdValues.Add(z) |> ignore
349-
329+
350330
return true
351331
}
352332
|> Property.checkBoolWith (PropertyConfig.withTests 100<tests> PropertyConfig.defaults)
353-
333+
354334
// Each generator should produce multiple different values
355335
// If the seed wasn't threaded properly, they would all produce the same value
356336
firstValues.Count > 10 |> Expect.isTrue

0 commit comments

Comments
 (0)