trackler 2.2.1.138 → 2.2.1.139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/crypto-square/description.md +23 -19
  4. data/problem-specifications/exercises/yacht/canonical-data.json +10 -1
  5. data/tracks/clojure/exercises/gigasecond/src/gigasecond.clj +5 -0
  6. data/tracks/clojure/exercises/grade-school/src/grade_school.clj +13 -0
  7. data/tracks/clojure/exercises/grains/src/grains.clj +9 -0
  8. data/tracks/clojure/exercises/minesweeper/src/minesweeper.clj +5 -0
  9. data/tracks/fsharp/docs/GENERATORS.md +12 -14
  10. data/tracks/fsharp/exercises/bowling/BowlingTest.fs +15 -15
  11. data/tracks/fsharp/exercises/perfect-numbers/PerfectNumbersTest.fs +11 -11
  12. data/tracks/fsharp/exercises/rna-transcription/Example.fs +7 -15
  13. data/tracks/fsharp/exercises/rna-transcription/RnaTranscription.fs +1 -1
  14. data/tracks/fsharp/exercises/rna-transcription/RnaTranscriptionTest.fs +5 -5
  15. data/tracks/fsharp/exercises/robot-simulator/RobotSimulatorTest.fs +34 -34
  16. data/tracks/fsharp/exercises/sublist/Example.fs +1 -1
  17. data/tracks/fsharp/exercises/sublist/Sublist.fs +1 -1
  18. data/tracks/fsharp/exercises/sublist/SublistTest.fs +17 -17
  19. data/tracks/fsharp/exercises/word-search/WordSearchTest.fs +56 -57
  20. data/tracks/fsharp/generators/CanonicalData.fs +14 -15
  21. data/tracks/fsharp/generators/Common.fs +4 -84
  22. data/tracks/fsharp/generators/Conversion.fs +75 -0
  23. data/tracks/fsharp/generators/Exercise.fs +15 -11
  24. data/tracks/fsharp/generators/Generators.fs +294 -468
  25. data/tracks/fsharp/generators/Generators.fsproj +2 -1
  26. data/tracks/fsharp/generators/Rendering.fs +169 -61
  27. data/tracks/fsharp/generators/Templates.fs +64 -0
  28. data/tracks/fsharp/generators/Track.fs +3 -3
  29. data/tracks/idris/exercises/accumulate/src/Example.idr +1 -1
  30. data/tracks/idris/exercises/accumulate/src/Test/Accumulate.idr +2 -2
  31. data/tracks/java/exercises/rna-transcription/.meta/hints.md +2 -0
  32. data/tracks/java/exercises/rna-transcription/README.md +6 -0
  33. data/tracks/nim/.gitignore +1 -0
  34. data/tracks/nim/config.json +38 -0
  35. data/tracks/nim/config/maintainers.json +10 -0
  36. data/tracks/nim/docs/ABOUT.md +7 -0
  37. data/tracks/nim/exercises/bob/README.md +2 -0
  38. data/tracks/nim/exercises/bob/bob_test.nim +31 -13
  39. data/tracks/nim/exercises/bob/example.nim +2 -2
  40. data/tracks/nim/exercises/gigasecond/README.md +22 -0
  41. data/tracks/nim/exercises/gigasecond/example.nim +4 -0
  42. data/tracks/nim/exercises/gigasecond/gigasecond_test.nim +32 -0
  43. data/tracks/nim/exercises/isogram/README.md +20 -0
  44. data/tracks/nim/exercises/isogram/example.nim +6 -0
  45. data/tracks/nim/exercises/isogram/isogram_test.nim +32 -0
  46. data/tracks/nim/exercises/space-age/README.md +24 -0
  47. data/tracks/nim/exercises/space-age/example.nim +17 -0
  48. data/tracks/nim/exercises/space-age/space_age_test.nim +29 -0
  49. data/tracks/nim/exercises/triangle/example.nim +22 -22
  50. data/tracks/nim/exercises/triangle/triangle_test.nim +32 -44
  51. metadata +19 -3
  52. data/tracks/fsharp/generators/Formatting.fs +0 -189
@@ -2,7 +2,6 @@ module Generators.CanonicalData
2
2
 
3
3
  open System
4
4
  open System.IO
5
- open System.Collections.Generic
6
5
  open Serilog
7
6
  open LibGit2Sharp
8
7
  open Newtonsoft.Json
@@ -10,10 +9,10 @@ open Newtonsoft.Json.Linq
10
9
  open Options
11
10
 
12
11
  type CanonicalDataCase =
13
- { Input: Map<string, obj>
14
- Expected: obj
12
+ { Input: Map<string, JToken>
13
+ Expected: JToken
15
14
  Property: string
16
- Properties: Map<string, obj>
15
+ Properties: Map<string, JToken>
17
16
  Description: string
18
17
  DescriptionPath: string list }
19
18
 
@@ -58,10 +57,14 @@ let private downloadData options =
58
57
 
59
58
  type CanonicalDataConverter() =
60
59
  inherit JsonConverter()
60
+
61
+ let rec parentsAndSelf (currentToken: JToken) =
62
+ let rec helper acc (token: JToken) =
63
+ match token with
64
+ | null -> acc
65
+ | _ -> helper (token::acc) token.Parent
61
66
 
62
- let jTokenToMap (jToken: JToken) =
63
- jToken.ToObject<IDictionary<string, obj>>()
64
- |> Dict.toMap
67
+ helper [] currentToken
65
68
 
66
69
  let createDescriptionPathFromJToken (jToken: JToken): string list =
67
70
  let descriptionFromJToken (currentToken: JToken) =
@@ -70,18 +73,14 @@ type CanonicalDataConverter() =
70
73
  | description -> Some (description.ToObject<string>())
71
74
 
72
75
  jToken
73
- |> Json.parentsAndSelf
76
+ |> parentsAndSelf
74
77
  |> List.choose descriptionFromJToken
75
78
 
76
- let createInputFromJToken (properties: Map<string, obj>) =
77
- properties.["input"] :?> JObject
78
- |> jTokenToMap
79
-
80
79
  let createCanonicalDataCaseFromJToken (jToken: JToken) =
81
- let properties = jTokenToMap jToken
80
+ let properties = Map.ofJToken jToken
82
81
 
83
- { Input = createInputFromJToken properties
84
- Expected = if properties.ContainsKey "expected" then properties.["expected"] else ("" :> obj)
82
+ { Input = Map.ofJToken properties.["input"]
83
+ Expected = properties.["expected"]
85
84
  Property = string properties.["property"]
86
85
  Properties = properties
87
86
  Description = string properties.["description"]
@@ -1,10 +1,6 @@
1
1
  [<AutoOpen>]
2
2
  module Generators.Common
3
3
 
4
- open System
5
- open Serilog
6
- open Newtonsoft.Json.Linq
7
-
8
4
  type TestMethod =
9
5
  { Skip: bool
10
6
  Name: string
@@ -32,86 +28,10 @@ type TestFileFormat =
32
28
  | Class
33
29
 
34
30
  module Logging =
31
+
32
+ open Serilog
33
+
35
34
  let setupLogger() =
36
35
  Log.Logger <- LoggerConfiguration()
37
36
  .WriteTo.LiterateConsole()
38
- .CreateLogger();
39
-
40
- let isInt64 (value: obj) =
41
- match value with
42
- | :? int64 -> true
43
- | _ -> false
44
-
45
- module Option =
46
- let ofPositiveInt (value: obj) =
47
- match value with
48
- | :? int64 as i -> if i < 0L then None else Some value
49
- | :? int32 as i -> if i < 0 then None else Some value
50
- | _ -> Some value
51
-
52
- let ofNonFalse (value: obj) =
53
- match value with
54
- | :? bool as b when not b -> None
55
- | _ -> Some value
56
-
57
- let ofNonError (value: obj) =
58
- match value with
59
- | :? JToken as jToken ->
60
- match jToken.SelectToken("error") |> isNull with
61
- | true -> Some value
62
- | false -> None
63
- | _ -> Some value
64
-
65
- let ofNonEmptyString (value: string) =
66
- match String.IsNullOrEmpty value with
67
- | true -> None
68
- | false -> Some value
69
-
70
- module String =
71
- open Humanizer
72
-
73
- let split (separator: string) (y: string) = y.Split(separator)
74
-
75
- let equals (x: string) (y: string) = String.Equals(x, y, StringComparison.OrdinalIgnoreCase)
76
-
77
- let dehumanize (str: string) = str.Dehumanize()
78
-
79
- let camelize (str: string) = str.Camelize()
80
-
81
- let upperCaseFirst (str: string) =
82
- match str with
83
- | "" -> str
84
- | _ -> sprintf "%c%s" (Char.ToUpper(str.[0])) str.[1..]
85
-
86
- let lowerCaseFirst (str: string) =
87
- match str with
88
- | "" -> str
89
- | _ -> sprintf "%c%s" (Char.ToLower(str.[0])) str.[1..]
90
-
91
- let replace (oldValue: string) (newValue: string) (str: string) =
92
- str.Replace(oldValue, newValue)
93
-
94
- let toLower (str: string) = str.ToLowerInvariant()
95
-
96
- module Json =
97
- let rec parentsAndSelf (currentToken: JToken) =
98
- let rec helper acc (token: JToken) =
99
- match token with
100
- | null -> acc
101
- | _ -> helper (token::acc) token.Parent
102
-
103
- helper [] currentToken
104
-
105
- module Dict =
106
-
107
- open System.Collections.Generic
108
-
109
- let toSeq d = d |> Seq.map (fun (KeyValue(k,v)) -> (k, v))
110
-
111
- let toMap d = d |> toSeq |> Map.ofSeq
112
-
113
- let ofMap (m: Map<'k,'v>) = new Dictionary<'k,'v>(m) :> IDictionary<'k,'v>
114
-
115
- let ofList (l: ('k * 'v) list) = new Dictionary<'k,'v>(l |> Map.ofList) :> IDictionary<'k,'v>
116
-
117
- let ofSeq (s: ('k * 'v) seq) = new Dictionary<'k,'v>(s |> Map.ofSeq) :> IDictionary<'k,'v>
37
+ .CreateLogger()
@@ -0,0 +1,75 @@
1
+ [<AutoOpen>]
2
+ module Generators.Conversion
3
+
4
+ open System
5
+ open Newtonsoft.Json.Linq
6
+
7
+ module Option =
8
+ let ofNonNegativeNumber (jToken: JToken) =
9
+ match jToken.Type with
10
+ | JTokenType.Integer -> if jToken.ToObject<int>() < 0 then None else Some jToken
11
+ | _ -> Some jToken
12
+
13
+ let ofNonFalseBoolean (jToken: JToken) =
14
+ match jToken.Type with
15
+ | JTokenType.Boolean -> if jToken.ToObject<bool>() then Some jToken else None
16
+ | _ -> Some jToken
17
+
18
+ let ofNonNull (jToken: JToken) =
19
+ match jToken.Type with
20
+ | JTokenType.Null -> None
21
+ | _ -> Some jToken
22
+
23
+ let ofNonErrorObject (jToken: JToken) =
24
+ match jToken.SelectToken("error") |> isNull with
25
+ | true -> Some jToken
26
+ | false -> None
27
+
28
+ let ofNonEmptyString (value: string) =
29
+ match String.IsNullOrEmpty value with
30
+ | true -> None
31
+ | false -> Some value
32
+
33
+ module String =
34
+ open Humanizer
35
+
36
+ let dehumanize (str: string) = str.Dehumanize()
37
+
38
+ let camelize (str: string) = str.Camelize()
39
+
40
+ let upperCaseFirst (str: string) =
41
+ match str with
42
+ | "" -> str
43
+ | _ -> sprintf "%c%s" (Char.ToUpper(str.[0])) str.[1..]
44
+
45
+ let lowerCaseFirst (str: string) =
46
+ match str with
47
+ | "" -> str
48
+ | _ -> sprintf "%c%s" (Char.ToLower(str.[0])) str.[1..]
49
+
50
+ let replace (oldValue: string) (newValue: string) (str: string) =
51
+ str.Replace(oldValue, newValue)
52
+
53
+ let toLower (str: string) = str.ToLowerInvariant()
54
+
55
+ let indent level str =
56
+ let oneLevelIndentation = " "
57
+ let indentation = String.replicate level oneLevelIndentation
58
+ sprintf "%s%s" indentation str
59
+
60
+ let enclose before after str = sprintf "%s%s%s" before str after
61
+
62
+ let enquote str = enclose "\"" "\"" str
63
+
64
+ let parenthesize str = enclose "(" ")" str
65
+
66
+ let split (separator: string) (str: string) = str.Split(separator)
67
+
68
+ module Map =
69
+
70
+ open System.Collections.Generic
71
+
72
+ let ofJToken<'TKey, 'TValue when 'TKey: comparison> (jToken: JToken) =
73
+ jToken.ToObject<IDictionary<'TKey, 'TValue>>()
74
+ |> Seq.map (fun (KeyValue(k,v)) -> (k, v))
75
+ |> Map.ofSeq
@@ -6,9 +6,8 @@ open System.Reflection
6
6
  open Newtonsoft.Json
7
7
  open Newtonsoft.Json.Linq
8
8
  open Humanizer
9
- open Serilog
10
- open Formatting
11
9
  open Rendering
10
+ open Templates
12
11
  open CanonicalData
13
12
  open Track
14
13
 
@@ -18,19 +17,19 @@ let private exerciseNameFromType (exerciseType: Type) = exerciseType.Name.Kebabe
18
17
  type GeneratorExercise() =
19
18
 
20
19
  // Customize rendered output
21
- abstract member RenderExpected : CanonicalDataCase * string * obj -> string
22
- abstract member RenderInput : CanonicalDataCase * string * obj -> string
20
+ abstract member RenderExpected : CanonicalDataCase * string * JToken -> string
21
+ abstract member RenderInput : CanonicalDataCase * string * JToken -> string
23
22
  abstract member RenderArrange : CanonicalDataCase -> string list
24
23
  abstract member RenderAssert : CanonicalDataCase -> string list
25
24
  abstract member RenderSut : CanonicalDataCase -> string
26
25
  abstract member RenderSetup : CanonicalData -> string
27
- abstract member RenderValue : CanonicalDataCase * string * obj -> string
26
+ abstract member RenderValue : CanonicalDataCase * string * JToken -> string
28
27
 
29
28
  // Utility methods to customize rendered output
30
29
  abstract member MapCanonicalDataCase : CanonicalDataCase -> CanonicalDataCase
31
30
  abstract member PropertiesUsedAsSutParameter : CanonicalDataCase -> string list
32
31
  abstract member PropertiesWithIdentifier : CanonicalDataCase -> string list
33
- abstract member IdentifierTypeAnnotation: CanonicalDataCase * string * obj -> string option
32
+ abstract member IdentifierTypeAnnotation: CanonicalDataCase * string * JToken -> string option
34
33
  abstract member AdditionalNamespaces : string list
35
34
  abstract member AssertTemplate : CanonicalDataCase -> string
36
35
  abstract member TestFileFormat: TestFileFormat
@@ -105,9 +104,14 @@ type GeneratorExercise() =
105
104
  | Class -> "TestMemberBody"
106
105
 
107
106
  default this.AssertTemplate canonicalDataCase =
108
- match canonicalDataCase.Expected with
109
- | :? JArray as jArray when jArray.Count = 0 && not (List.contains "expected" (this.PropertiesWithIdentifier canonicalDataCase)) -> "AssertEmpty"
110
- | _ -> "AssertEqual"
107
+ let expectedIsArray = canonicalDataCase.Expected.Type = JTokenType.Array
108
+ let expectedIsEmpty = Seq.isEmpty canonicalDataCase.Expected
109
+ let expectedHasIdentifier = List.contains "expected" (this.PropertiesWithIdentifier canonicalDataCase)
110
+
111
+ if expectedIsArray && expectedIsEmpty && not expectedHasIdentifier then
112
+ "AssertEmpty"
113
+ else
114
+ "AssertEqual"
111
115
 
112
116
  default __.TestFileFormat = TestFileFormat.Module
113
117
 
@@ -145,7 +149,7 @@ type GeneratorExercise() =
145
149
 
146
150
  // Generic value/identifier rendering methods
147
151
 
148
- default __.RenderValue (_, _, value) = formatValue value
152
+ default __.RenderValue (_, _, value) = Obj.render value
149
153
 
150
154
  member this.RenderValueOrIdentifier (canonicalDataCase, key, value) =
151
155
  let properties = this.PropertiesWithIdentifier canonicalDataCase
@@ -172,7 +176,7 @@ type GeneratorExercise() =
172
176
 
173
177
  match this.IdentifierTypeAnnotation (canonicalDataCase, key, value) with
174
178
  | Some identifierType ->
175
- identifier |> addTypeAnnotation identifierType
179
+ sprintf "%s: %s" identifier identifierType
176
180
  | None ->
177
181
  identifier
178
182
 
@@ -4,33 +4,35 @@ open System
4
4
  open System.Globalization
5
5
  open Newtonsoft.Json.Linq
6
6
  open CanonicalData
7
- open Formatting
7
+ open Conversion
8
8
  open Rendering
9
+ open Templates
9
10
  open Exercise
11
+ open Generators.Common
10
12
 
11
13
  type Acronym() =
12
14
  inherit GeneratorExercise()
13
15
 
14
- type AllYourBase() =
16
+ type AllYourBase() =
15
17
  inherit GeneratorExercise()
16
18
 
17
19
  override __.RenderExpected (_, _, value) =
18
- value
19
- |> Option.ofNonError
20
- |> formatValue
20
+ value
21
+ |> Option.ofNonErrorObject
22
+ |> Option.render
21
23
 
22
24
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
23
25
 
24
26
  type Allergies() =
25
27
  inherit GeneratorExercise()
26
28
 
27
- let toAllergen (jToken: JToken) = sprintf "Allergen.%s" (jToken.ToString() |> String.dehumanize)
29
+ let renderAllergenEnum (jToken: JToken) = Obj.renderEnum "Allergen" jToken
28
30
 
29
31
  let renderAllergicToAssert canonicalDataCase (jToken: JToken) =
30
- let substance = jToken.["substance"] |> toAllergen
31
- let score = canonicalDataCase.Input.["score"] :?> int64
32
+ let substance = renderAllergenEnum jToken.["substance"]
33
+ let score = canonicalDataCase.Input.["score"].ToObject<int>()
32
34
  let sut = sprintf "allergicTo %d %s" score substance
33
- let expected = jToken.Value<bool>("result") |> formatBool
35
+ let expected = jToken.Value<bool>("result") |> Bool.render
34
36
 
35
37
  { Sut = sut; Expected = expected }
36
38
  |> renderPartialTemplate "AssertEqual"
@@ -38,45 +40,24 @@ type Allergies() =
38
40
  override __.RenderAssert canonicalDataCase =
39
41
  match canonicalDataCase.Property with
40
42
  | "allergicTo" ->
41
- canonicalDataCase.Expected :?> JArray
43
+ canonicalDataCase.Expected
42
44
  |> Seq.map (renderAllergicToAssert canonicalDataCase)
43
45
  |> Seq.toList
44
46
  | _ ->
45
47
  base.RenderAssert canonicalDataCase
46
48
 
47
- override __.RenderExpected (canonicalDataCase, key, value) =
48
- if (canonicalDataCase.Property = "list") then
49
- canonicalDataCase.Expected :?> JArray
50
- |> Seq.map toAllergen
51
- |> formatList
52
- else
53
- base.RenderExpected (canonicalDataCase, key, value)
54
-
55
- override __.RenderInput (canonicalDataCase, key, value) =
56
- match key with
57
- | "substance" -> string value
58
- | _ -> base.RenderInput (canonicalDataCase, key, value)
49
+ override __.RenderExpected (canonicalDataCase, key, value) =
50
+ match canonicalDataCase.Property with
51
+ | "list" -> List.mapRender renderAllergenEnum canonicalDataCase.Expected
52
+ | _ -> base.RenderExpected (canonicalDataCase, key, value)
59
53
 
60
54
  type Alphametics() =
61
55
  inherit GeneratorExercise()
62
56
 
63
- member __.FormatMap<'TKey, 'TValue> (value: obj) =
64
- if isNull value then
65
- "None"
66
- else
67
- let input = value :?> JObject
68
- let dict = input.ToObject<Collections.Generic.Dictionary<'TKey, 'TValue>>();
69
- let formattedList =
70
- dict
71
- |> Seq.map (fun kv -> formatTuple (kv.Key, kv.Value))
72
- |> formatMultiLineList
73
-
74
- if (formattedList.Contains("\n")) then
75
- sprintf "%s\n%s\n%s" formattedList (indent 2 "|> Map.ofList") (indent 2 "|> Some")
76
- else
77
- sprintf "%s |> Map.ofList |> Some" formattedList
78
-
79
- override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
57
+ override __.RenderExpected (_, _, value) =
58
+ value
59
+ |> Option.ofNonNull
60
+ |> Map.renderOption<char, int>
80
61
 
81
62
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
82
63
 
@@ -96,10 +77,7 @@ type BeerSong() =
96
77
 
97
78
  override __.PropertiesWithIdentifier _ = ["expected"]
98
79
 
99
- override __.RenderExpected (_, _, value) =
100
- value :?> JArray
101
- |> Seq.map formatValue
102
- |> formatMultiLineList
80
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
103
81
 
104
82
  type BinarySearch() =
105
83
  inherit GeneratorExercise()
@@ -108,19 +86,18 @@ type BinarySearch() =
108
86
 
109
87
  override __.RenderValue (canonicalDataCase, key, value) =
110
88
  match key with
111
- | "array" ->
112
- (value :?> JToken).ToObject<string []>() |> formatArray
113
- | "expected" ->
114
- match string value with
115
- | "-1" -> None |> formatOption
116
- | x -> Some x |> formatOption
89
+ | "array" -> Array.render value
90
+ | "expected" ->
91
+ value
92
+ |> Option.ofNonNegativeNumber
93
+ |> Option.render
117
94
  | _ ->
118
95
  base.RenderValue (canonicalDataCase, key, value)
119
96
 
120
97
  type BinarySearchTree() =
121
98
  inherit GeneratorExercise()
122
99
 
123
- let rec renderAssertions previousPaths (tree: JObject) =
100
+ let rec renderAssertions previousPaths (tree: JToken) =
124
101
  let previousPath = previousPaths |> List.rev |> String.concat " |> "
125
102
  let rootPath = List.length previousPaths = 1
126
103
 
@@ -133,8 +110,7 @@ type BinarySearchTree() =
133
110
  let expected = if rootPath then failwith "Invalid data" else "None"
134
111
  [ sprintf "%s |> %s |> should equal %s" previousPath dataPath expected ]
135
112
  | _ ->
136
- let data = (data :?> JValue).ToObject<int>()
137
- let expected = if rootPath then string data else sprintf "(Some %d)" data
113
+ let expected = if rootPath then string data else sprintf "(Some %s)" (string data)
138
114
  [ sprintf "%s |> %s |> should equal %s" previousPath dataPath expected ]
139
115
 
140
116
  let renderNodeAssertions nodeName (node: JToken) =
@@ -144,7 +120,7 @@ type BinarySearchTree() =
144
120
  | JTokenType.Null ->
145
121
  [ sprintf "%s |> %s |> should equal None" previousPath nodePath ]
146
122
  | _ ->
147
- renderAssertions (nodePath :: previousPaths) (node :?> JObject)
123
+ renderAssertions (nodePath :: previousPaths) node
148
124
 
149
125
  [ renderDataAssertions
150
126
  renderNodeAssertions "left" tree.["left"]
@@ -154,19 +130,18 @@ type BinarySearchTree() =
154
130
  override __.RenderAssert canonicalDataCase =
155
131
  match canonicalDataCase.Property with
156
132
  | "data" ->
157
- canonicalDataCase.Expected :?> JObject
133
+ canonicalDataCase.Expected
158
134
  |> renderAssertions ["treeData"]
159
135
  | _ -> base.RenderAssert canonicalDataCase
160
136
 
161
137
  override __.RenderInput (_, _, value) =
162
- value :?> JArray
163
- |> Seq.map string
164
- |> formatList
138
+ value
139
+ |> List.mapRender string
165
140
  |> sprintf "create %s"
166
141
 
167
142
  override __.RenderExpected (canonicalDataCase, key, value) =
168
- match value with
169
- | :? JArray as jArray -> jArray |> Seq.map string |> formatList
143
+ match value.Type with
144
+ | JTokenType.Array -> value.ToObject<int list>() |> List.render
170
145
  | _ -> base.RenderExpected (canonicalDataCase, key, value)
171
146
 
172
147
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
@@ -177,9 +152,7 @@ type Bob() =
177
152
  type BookStore() =
178
153
  inherit GeneratorExercise()
179
154
 
180
- let formatFloat (value:obj) = value :?> int64 |> (fun x -> float x / 100.0) |> sprintf "%.2f"
181
-
182
- override __.RenderExpected (_, _, value) = formatFloat value
155
+ override __.RenderExpected (_, _, value) = value.ToObject<float>() / 100.0 |> sprintf "%.2f"
183
156
 
184
157
  override __.PropertiesUsedAsSutParameter canonicalDataCase =
185
158
  base.PropertiesUsedAsSutParameter canonicalDataCase |> List.except ["targetgrouping"]
@@ -187,17 +160,17 @@ type BookStore() =
187
160
  type Bowling() =
188
161
  inherit GeneratorExercise()
189
162
 
190
- override __.RenderSut _ ="score game"
163
+ override __.RenderSut _ = "score game"
191
164
 
192
165
  override __.RenderSetup _ =
193
166
  "let rollMany rolls game = List.fold (fun game pins -> roll pins game) game rolls"
194
167
 
195
168
  override __.RenderArrange canonicalDataCase =
196
169
  seq {
197
- let arr = (canonicalDataCase.Input.["previousRolls"] :?> JToken).ToObject<string[]>()
198
- yield sprintf "let rolls = %s" (formatList arr)
170
+ let previousRolls = canonicalDataCase.Input.["previousRolls"].ToObject<int list>() |> List.render
171
+ yield sprintf "let rolls = %s" previousRolls
199
172
  if canonicalDataCase.Input.ContainsKey "roll" then
200
- let roll = canonicalDataCase.Input.["roll"] :?> int64
173
+ let roll = canonicalDataCase.Input.["roll"].ToObject<int>()
201
174
  yield sprintf "let startingRolls = rollMany rolls (newGame())"
202
175
  yield sprintf "let game = roll %i startingRolls" roll
203
176
  else
@@ -205,8 +178,10 @@ type Bowling() =
205
178
  }
206
179
  |> Seq.toList
207
180
 
208
- override __.RenderExpected (_, _, value) =
209
- if value :? JObject then "None" else sprintf "<| Some %s" (formatValue value)
181
+ override __.RenderExpected (_, _, value) =
182
+ value
183
+ |> Option.ofNonErrorObject
184
+ |> Option.renderParenthesized
210
185
 
211
186
  type BracketPush() =
212
187
  inherit GeneratorExercise()
@@ -215,16 +190,17 @@ type Change() =
215
190
  inherit GeneratorExercise()
216
191
 
217
192
  override __.RenderExpected (_, _, value) =
218
- let convertToOption = if value :? JArray then Option.ofObj else Option.ofPositiveInt
219
- value |> convertToOption |> formatValue
193
+ value
194
+ |> Option.ofNonNegativeNumber
195
+ |> Option.render
220
196
 
221
197
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
222
198
 
223
199
  override __.IdentifierTypeAnnotation (canonicalDataCase, key, _) =
224
200
  match key with
225
201
  | "expected" ->
226
- match canonicalDataCase.Input.["target"] :?> int64 with
227
- | 0L -> Some "int list option"
202
+ match canonicalDataCase.Input.["target"].ToObject<int>() with
203
+ | 0 -> Some "int list option"
228
204
  | _ -> None
229
205
  | _ -> None
230
206
 
@@ -240,12 +216,12 @@ type CircularBuffer() =
240
216
 
241
217
  override this.RenderArrange canonicalDataCase =
242
218
  seq {
243
- yield sprintf "let buffer1 = mkCircularBuffer %i" (canonicalDataCase.Input.["capacity"] :?> int64)
244
- let operations = (canonicalDataCase.Input.["operations"] :?> JArray)
219
+ yield sprintf "let buffer1 = mkCircularBuffer %i" (canonicalDataCase.Input.["capacity"].ToObject<int>())
220
+ let operations = canonicalDataCase.Input.["operations"]
245
221
  let mutable ind = 2
246
- let lastInd = operations.Count + 1
222
+ let lastInd = Seq.length operations + 1
247
223
  for op in operations do
248
- let dict = (op :?> JObject).ToObject<Collections.Generic.Dictionary<string, JToken>>();
224
+ let dict = (op :?> JObject).ToObject<Collections.Generic.Dictionary<string, JToken>>()
249
225
  let funcName = dict.["operation"].ToObject<string>()
250
226
  match funcName with
251
227
  | "write" as operation ->
@@ -262,7 +238,7 @@ type CircularBuffer() =
262
238
  | true, false ->
263
239
  yield this.ExceptionCheck command
264
240
  | _, _ ->
265
- let expected = dict.["expected"].ToObject<int64>()
241
+ let expected = dict.["expected"].ToObject<int>()
266
242
  if ind = lastInd then
267
243
  yield sprintf "let (val%i, _) = %s" ind command
268
244
  else
@@ -281,14 +257,13 @@ type CircularBuffer() =
281
257
  type Clock() =
282
258
  inherit GeneratorExercise()
283
259
 
284
- let createClock (value:obj) =
285
- let clock = value :?> JObject
286
- let hour = clock.["hour"].ToObject<string>()
287
- let minute = clock.["minute"].ToObject<string>()
260
+ let createClock (value: JToken) =
261
+ let hour = value.["hour"].ToObject<string>()
262
+ let minute = value.["minute"].ToObject<string>()
288
263
  sprintf "create %s %s" hour minute
289
264
 
290
- member private this.RenderPropertyValue canonicalDataCase property =
291
- this.RenderSutParameter (canonicalDataCase, property, Map.find property canonicalDataCase.Input)
265
+ member private this.RenderPropertyValue canonicalDataCase propertyName =
266
+ this.RenderSutParameter (canonicalDataCase, propertyName, Map.find propertyName canonicalDataCase.Input)
292
267
 
293
268
  override __.PropertiesWithIdentifier _ = ["clock1"; "clock2"]
294
269
 
@@ -336,26 +311,26 @@ type ComplexNumbers() =
336
311
  sprintf "(create %s %s)" (renderNumber input.[0]) (renderNumber input.[1])
337
312
 
338
313
  override __.RenderValue (canonicalDataCase, key, value) =
339
- match value with
340
- | :? JArray as jArray -> renderComplexNumber jArray
341
- | :? int64 as i -> sprintf "%d.0" i
314
+ match value.Type with
315
+ | JTokenType.Array -> renderComplexNumber (value.ToObject<JArray>())
316
+ | JTokenType.Integer -> sprintf "%d.0" (value.ToObject<int>())
342
317
  | _ -> base.RenderValue (canonicalDataCase, key, value)
343
318
 
344
319
  override __.RenderAssert canonicalDataCase =
345
- match canonicalDataCase.Expected with
346
- | :? JArray as jArray ->
320
+ match canonicalDataCase.Expected.Type with
321
+ | JTokenType.Array ->
347
322
  let renderAssertion testedFunction expected =
348
323
  { Sut = sprintf "%s sut" testedFunction; Expected = expected }
349
324
  |> renderPartialTemplate "AssertEqualWithin"
350
325
 
351
- [ jArray.[0] |> renderNumber |> renderAssertion "real"
352
- jArray.[1] |> renderNumber |> renderAssertion "imaginary" ]
326
+ [ canonicalDataCase.Expected.[0] |> renderNumber |> renderAssertion "real"
327
+ canonicalDataCase.Expected.[1] |> renderNumber |> renderAssertion "imaginary" ]
353
328
  | _ ->
354
329
  base.RenderAssert(canonicalDataCase)
355
330
 
356
331
  override __.PropertiesWithIdentifier canonicalDataCase =
357
- match canonicalDataCase.Expected with
358
- | :? JArray -> ["sut"]
332
+ match canonicalDataCase.Expected.Type with
333
+ | JTokenType.Array -> ["sut"]
359
334
  | _ -> base.PropertiesWithIdentifier canonicalDataCase
360
335
 
361
336
  override __.AdditionalNamespaces = [typeof<Math>.Namespace]
@@ -370,12 +345,12 @@ type Connect() =
370
345
  | _ -> "None"
371
346
 
372
347
  override __.RenderInput (_, _, value) =
373
- let lines = (value :?> JArray).ToObject<string seq>() |> List.ofSeq
348
+ let lines = value.ToObject<string list>()
374
349
  let padSize = List.last lines |> String.length
375
350
 
376
- lines
377
- |> List.map (fun line -> line.PadRight(padSize) |> formatValue)
378
- |> formatMultiLineList
351
+ lines
352
+ |> Seq.map (fun line -> line.PadRight(padSize))
353
+ |> List.renderMultiLine
379
354
 
380
355
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
381
356
 
@@ -383,10 +358,9 @@ type CollatzConjecture() =
383
358
  inherit GeneratorExercise()
384
359
 
385
360
  override __.RenderExpected (_, _, value) =
386
- value
387
- |> Option.ofNonError
388
- |> formatValue
389
- |> parenthesizeOption
361
+ value
362
+ |> Option.ofNonErrorObject
363
+ |> Option.renderParenthesized
390
364
 
391
365
  type CryptoSquare() =
392
366
  inherit GeneratorExercise()
@@ -398,9 +372,9 @@ type CustomSet() =
398
372
 
399
373
  override __.AssertTemplate _ = "AssertEqual"
400
374
 
401
- member __.RenderSet (jToken: obj) =
402
- (jToken :?> JToken).ToObject<seq<string>>()
403
- |> formatList
375
+ member __.RenderSet (jToken: JToken) =
376
+ jToken
377
+ |> List.render
404
378
  |> sprintf "CustomSet.fromList %s"
405
379
 
406
380
  override this.RenderSut canonicalDataCase =
@@ -413,7 +387,7 @@ type CustomSet() =
413
387
  match canonicalDataCase.Property with
414
388
  | "add" | "intersection" | "difference" | "union" ->
415
389
  "true"
416
- | _ -> formatValue canonicalDataCase.Expected
390
+ | _ -> Obj.render canonicalDataCase.Expected
417
391
 
418
392
  override this.RenderArrange canonicalDataCase =
419
393
  let arrangeLines =
@@ -427,7 +401,7 @@ type CustomSet() =
427
401
  | "add" -> "insert"
428
402
  | s -> s
429
403
  let setVar = sprintf "let setValue = %s" (this.RenderSet canonicalDataCase.Input.["set"])
430
- let valueVar = sprintf "let element = %s" (formatValue canonicalDataCase.Input.["element"])
404
+ let valueVar = sprintf "let element = %s" (Obj.render canonicalDataCase.Input.["element"])
431
405
  let resultVar = sprintf "let %s = CustomSet.%s element setValue" this.SutName methodName
432
406
  [ setVar; valueVar; resultVar ]
433
407
  | "intersection" | "difference" | "union" | "disjoint" | "subset" | "equal" ->
@@ -460,37 +434,20 @@ type DifferenceOfSquares() =
460
434
  type Dominoes() =
461
435
  inherit GeneratorExercise()
462
436
 
463
- let formatAsTuple (value:obj) =
464
- let items = value :?> obj list
465
- formatTuple (List.item 0 items, List.item 1 items)
437
+ let formatAsTuple (value: JToken) =
438
+ let items = value.ToObject<int list>()
439
+ Obj.render (items.[0], items.[1])
466
440
 
467
- override __.RenderInput (_, _, value) =
468
- value :?> JArray
469
- |> normalizeJArray
470
- |> Seq.map formatAsTuple
471
- |> formatList
441
+ override __.RenderInput (_, _, value) = List.mapRender formatAsTuple value
472
442
 
473
443
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
474
444
 
475
445
  type Etl() =
476
446
  inherit GeneratorExercise()
477
447
 
478
- member __.FormatMap<'TKey, 'TValue> (value: obj) =
479
- let input = value :?> JObject
480
- let dict = input.ToObject<Collections.Generic.Dictionary<'TKey, 'TValue>>();
481
- let formattedList =
482
- dict
483
- |> Seq.map (fun kv -> formatTuple (kv.Key, kv.Value))
484
- |> formatMultiLineList
485
-
486
- if (formattedList.Contains("\n")) then
487
- sprintf "%s\n%s" formattedList (indent 2 "|> Map.ofList")
488
- else
489
- sprintf "%s |> Map.ofList" formattedList
448
+ override __.RenderInput (_, _, value) = Map.render<int, char list> value
490
449
 
491
- override this.RenderInput (_, _, value) = this.FormatMap<int, List<char>> value
492
-
493
- override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
450
+ override __.RenderExpected (_, _, value) = Map.render<char, int> value
494
451
 
495
452
  override __.MapCanonicalDataCase canonicalDataCase =
496
453
  { canonicalDataCase with Input = Map.empty |> Map.add "lettersByScore" (canonicalDataCase.Properties.["input"]) }
@@ -504,10 +461,7 @@ type FoodChain() =
504
461
 
505
462
  override __.PropertiesWithIdentifier _ = ["expected"]
506
463
 
507
- override __.RenderExpected (_, _, value) =
508
- value :?> JArray
509
- |> Seq.map formatValue
510
- |> formatMultiLineList
464
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
511
465
 
512
466
  type Forth() =
513
467
  inherit GeneratorExercise()
@@ -516,11 +470,13 @@ type Forth() =
516
470
 
517
471
  override __.RenderExpected (_, _, value) =
518
472
  value
519
- |> Option.ofObj
520
- |> formatValue
473
+ |> Option.ofNonNull
474
+ |> Option.render
521
475
 
522
476
  override __.IdentifierTypeAnnotation (_, _, value) =
523
- match value :?> JArray|> Option.ofObj |> Option.map Seq.isEmpty with
477
+ let isEmptyList = value |> Option.ofNonNull |> Option.map Seq.isEmpty
478
+
479
+ match isEmptyList with
524
480
  | Some true -> Some "int list option"
525
481
  | _ -> None
526
482
 
@@ -529,58 +485,51 @@ type Forth() =
529
485
  type Gigasecond() =
530
486
  inherit GeneratorExercise()
531
487
 
532
- override __.RenderExpected (_, _, value) = value :?> DateTime |> formatDateTime |> parenthesize
488
+ override __.RenderExpected (_, _, value) =
489
+ value.ToObject<DateTime>()
490
+ |> DateTime.renderParenthesized
533
491
 
534
492
  override __.RenderInput (_, _, value) =
535
- DateTime.Parse(string value, CultureInfo.InvariantCulture) |> formatDateTime |> parenthesize
493
+ DateTime.Parse(string value, CultureInfo.InvariantCulture)
494
+ |> DateTime.renderParenthesized
536
495
 
537
496
  override __.AdditionalNamespaces = [typeof<DateTime>.Namespace]
538
497
 
539
498
  type GoCounting() =
540
499
  inherit GeneratorExercise()
541
500
 
542
- let renderOwner (value: JToken) =
543
- value
544
- |> string
545
- |> String.toLower
546
- |> String.upperCaseFirst
547
- |> sprintf "Owner.%s"
501
+ let renderOwner (value: JToken) = Obj.renderEnum "Owner" (string value |> String.toLower)
548
502
 
549
503
  let renderTerritoryPosition (value: JToken) =
550
- let arr = value :?> JArray
551
- (arr.[0].ToObject<int>(), arr.[1].ToObject<int>())
552
- |> formatValue
553
-
554
- let renderTerritory (value: JToken) =
555
- value :?> JArray
556
- |> Seq.map renderTerritoryPosition
557
- |> formatList
558
-
559
- let renderTerritoryWithOwner (value: obj) =
560
- let expected = value :?> JObject
561
- let owner = expected.["owner"] |> renderOwner
562
- let territory = expected.["territory"] |> renderTerritory
504
+ let arr = value.ToObject<int list>()
505
+ Obj.render (arr.[0], arr.[1])
506
+
507
+ let renderTerritory (value: JToken) = List.mapRender renderTerritoryPosition value
508
+
509
+ let renderTerritoryWithOwner (value: JToken) =
510
+ let owner = renderOwner value.["owner"]
511
+ let territory = renderTerritory value.["territory"]
563
512
  sprintf "(%s, %s)" owner territory
564
513
 
565
- let renderExpectedTerritory (value: obj) =
566
- match Option.ofNonError value with
514
+ let renderExpectedTerritory (expected: JToken) =
515
+ match Option.ofNonErrorObject expected with
567
516
  | None -> "Option.None"
568
517
  | Some expected -> expected |> renderTerritoryWithOwner |> sprintf "Option.Some %s"
569
518
 
570
- let renderExpectedTerritories (value: obj) =
571
- let expected = value :?> JObject
519
+ let renderExpectedTerritories (expected: JToken) =
572
520
  let black = sprintf "(Owner.Black, %s)" (expected.["territoryBlack"] |> renderTerritory)
573
521
  let white = sprintf "(Owner.White, %s)" (expected.["territoryWhite"] |> renderTerritory)
574
522
  let none = sprintf "(Owner.None, %s)" (expected.["territoryNone"] |> renderTerritory)
575
523
 
576
- let formattedList = formatMultiLineList [black; white; none]
577
- sprintf "%s\n%s" formattedList (indent 2 "|> Map.ofList")
524
+ let formattedList = List.mapRenderMultiLine id [black; white; none]
525
+ sprintf "%s\n%s" formattedList (String.indent 2 "|> Map.ofList")
578
526
 
579
- let territoryPosition (input: Map<string, obj>) =
527
+ let territoryPosition (input: Map<string, JToken>) =
580
528
  let valueToInt key = input |> Map.find key |> string |> int
581
- (valueToInt "x", valueToInt "y") |> box
529
+ let position = sprintf "{ \"x\": %d, \"y\": %d }" (valueToInt "x") (valueToInt "y")
530
+ JToken.Parse(position)
582
531
 
583
- let mapTerritoryInput (input: Map<string, obj>) =
532
+ let mapTerritoryInput (input: Map<string, JToken>) =
584
533
  input
585
534
  |> Map.remove "x"
586
535
  |> Map.remove "y"
@@ -593,10 +542,10 @@ type GoCounting() =
593
542
 
594
543
  override __.RenderInput (canonicalDataCase, key, value) =
595
544
  match key with
596
- | "board" ->
597
- value :?> JArray
598
- |> Seq.map formatValue
599
- |> formatMultiLineList
545
+ | "board" -> List.renderMultiLine value
546
+ | "position" ->
547
+ (value.SelectToken("x").ToObject<int>(), value.SelectToken("y").ToObject<int>())
548
+ |> Obj.render
600
549
  | _ ->
601
550
  base.RenderInput (canonicalDataCase, key, value)
602
551
 
@@ -611,10 +560,10 @@ type GoCounting() =
611
560
  override __.IdentifierTypeAnnotation (canonicalDataCase, key, value) =
612
561
  match canonicalDataCase.Property, key with
613
562
  | "territory", "expected" ->
614
- match Option.ofNonError value with
563
+ match Option.ofNonErrorObject value with
615
564
  | None -> None
616
565
  | Some _ ->
617
- if (value :?> JObject).["territory"] :?> JArray |> Seq.isEmpty then
566
+ if Seq.isEmpty value.["territory"] then
618
567
  Some "(Owner * (int * int) list) option"
619
568
  else
620
569
  None
@@ -635,12 +584,15 @@ type Grains() =
635
584
  type Grep() =
636
585
  inherit GeneratorExercise()
637
586
 
587
+ let indentExpected expected =
588
+ expected
589
+ |> String.split "\n"
590
+ |> Array.mapi (fun i part -> if i = 0 then part else String.indent 1 part)
591
+ |> String.concat "\n"
592
+
638
593
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
639
594
 
640
- override __.RenderExpected (_, _, value) =
641
- value :?> JArray
642
- |> Seq.map formatValue
643
- |> formatMultiLineListWithIndentation 3
595
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value |> indentExpected
644
596
 
645
597
  override __.RenderSetup _ = renderPartialTemplate "Generators/GrepSetup" Map.empty<string, obj>
646
598
 
@@ -650,7 +602,7 @@ type Grep() =
650
602
  override __.IdentifierTypeAnnotation (canonicalDataCase, key, value) =
651
603
  match key with
652
604
  | "expected" ->
653
- match value :?> JArray |> Seq.isEmpty with
605
+ match Seq.isEmpty value with
654
606
  | true -> Some "string list"
655
607
  | false -> None
656
608
  | _ ->
@@ -664,10 +616,9 @@ type Hamming() =
664
616
  inherit GeneratorExercise()
665
617
 
666
618
  override __.RenderExpected (_, _, value) =
667
- value
668
- |> Option.ofNonError
669
- |> formatValue
670
- |> parenthesizeOption
619
+ value
620
+ |> Option.ofNonErrorObject
621
+ |> Option.renderParenthesized
671
622
 
672
623
  type HelloWorld() =
673
624
  inherit GeneratorExercise()
@@ -679,10 +630,7 @@ type House() =
679
630
 
680
631
  override __.PropertiesWithIdentifier _ = ["expected"]
681
632
 
682
- override __.RenderExpected (_, _, value) =
683
- value :?> JArray
684
- |> Seq.map formatValue
685
- |> formatMultiLineList
633
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
686
634
 
687
635
  type IsbnVerifier() =
688
636
  inherit GeneratorExercise()
@@ -693,12 +641,9 @@ type Isogram() =
693
641
  type KindergartenGarden() =
694
642
  inherit GeneratorExercise()
695
643
 
696
- let toPlant (jToken: JToken) = sprintf "Plant.%s" (jToken.ToString() |> String.dehumanize)
644
+ let renderPlantEnum value = Obj.renderEnum "Plant" value
697
645
 
698
- override __.RenderExpected (_, _, value) =
699
- value :?> JArray
700
- |> Seq.map toPlant
701
- |> formatList
646
+ override __.RenderExpected (_, _, value) = List.mapRender renderPlantEnum value
702
647
 
703
648
  override __.PropertiesWithIdentifier _ = ["student"; "diagram"; "expected"]
704
649
 
@@ -710,10 +655,9 @@ type LargestSeriesProduct() =
710
655
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
711
656
 
712
657
  override __.RenderExpected (_, _, value) =
713
- value
714
- |> Option.ofPositiveInt
715
- |> formatValue
716
- |> parenthesizeOption
658
+ value
659
+ |> Option.ofNonNegativeNumber
660
+ |> Option.renderParenthesized
717
661
 
718
662
  type Leap() =
719
663
  inherit GeneratorExercise()
@@ -757,17 +701,13 @@ type Meetup() =
757
701
 
758
702
  override __.RenderExpected (_, _, value) =
759
703
  DateTime.Parse(string value)
760
- |> formatDateTime
761
- |> parenthesize
704
+ |> DateTime.renderParenthesized
762
705
 
763
706
  override __.RenderInput (canonicalDataCase, key, value) =
764
707
  match key with
765
- | "dayofweek" ->
766
- sprintf "DayOfWeek.%s" (string canonicalDataCase.Input.["dayofweek"])
767
- | "week" ->
768
- sprintf "Week.%s" (string canonicalDataCase.Input.["week"] |> String.upperCaseFirst)
769
- | _ ->
770
- base.RenderInput (canonicalDataCase, key, value)
708
+ | "dayofweek" -> Obj.renderEnum "DayOfWeek" canonicalDataCase.Input.["dayofweek"]
709
+ | "week" -> Obj.renderEnum "Week" canonicalDataCase.Input.["week"]
710
+ | _ -> base.RenderInput (canonicalDataCase, key, value)
771
711
 
772
712
  override __.PropertiesUsedAsSutParameter _ = ["year"; "month"; "week"; "dayofweek"]
773
713
 
@@ -776,19 +716,14 @@ type Meetup() =
776
716
  type Minesweeper() =
777
717
  inherit GeneratorExercise()
778
718
 
779
- let renderValue (value: obj) =
780
- value :?> JArray
781
- |> Seq.map formatValue
782
- |> formatMultiLineList
783
-
784
- override __.RenderInput (_, _, value) = renderValue value
719
+ override __.RenderInput (_, _, value) = List.renderMultiLine value
785
720
 
786
- override __.RenderExpected (_, _, value) = renderValue value
721
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
787
722
 
788
723
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
789
724
 
790
725
  override __.IdentifierTypeAnnotation (_, _, value) =
791
- match value :?> JArray |> Seq.isEmpty with
726
+ match Seq.isEmpty value with
792
727
  | true -> Some "string list"
793
728
  | false -> None
794
729
 
@@ -797,31 +732,16 @@ type NthPrime() =
797
732
 
798
733
  override __.RenderExpected (_, _, value) =
799
734
  value
800
- |> Option.ofNonError
801
- |> formatValue
802
- |> parenthesizeOption
735
+ |> Option.ofNonErrorObject
736
+ |> Option.renderParenthesized
803
737
 
804
738
  type NucleotideCount() =
805
739
  inherit GeneratorExercise()
806
740
 
807
- member __.FormatMap<'TKey, 'TValue> (value: obj) =
808
- match Option.ofNonError value with
809
- | None ->
810
- "None"
811
- | _ ->
812
- let input = value :?> JObject
813
- let dict = input.ToObject<Collections.Generic.Dictionary<'TKey, 'TValue>>();
814
- let formattedList =
815
- dict
816
- |> Seq.map (fun kv -> formatTuple (kv.Key, kv.Value))
817
- |> formatMultiLineList
818
-
819
- if (formattedList.Contains("\n")) then
820
- sprintf "%s\n%s\n%s" formattedList (indent 2 "|> Map.ofList") (indent 2 "|> Some")
821
- else
822
- sprintf "%s |> Map.ofList |> Some" formattedList
823
-
824
- override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
741
+ override __.RenderExpected (_, _, value) =
742
+ value
743
+ |> Option.ofNonErrorObject
744
+ |> Map.renderOption<char, int>
825
745
 
826
746
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
827
747
 
@@ -832,15 +752,10 @@ type OcrNumbers() =
832
752
 
833
753
  override __.RenderExpected (_, _, value) =
834
754
  value
835
- |> Option.ofPositiveInt
836
- |> formatValue
837
- |> parenthesizeOption
755
+ |> Option.ofNonNegativeNumber
756
+ |> Option.renderParenthesized
838
757
 
839
- override __.RenderInput (_, _, value) =
840
- value :?> JArray
841
- |> normalizeJArray
842
- |> Seq.map formatValue
843
- |> formatMultiLineList
758
+ override __.RenderInput (_, _, value) = List.renderMultiLine value
844
759
 
845
760
  type Pangram() =
846
761
  inherit GeneratorExercise()
@@ -848,28 +763,22 @@ type Pangram() =
848
763
  type PalindromeProducts() =
849
764
  inherit GeneratorExercise()
850
765
 
851
- let toFactors (value: obj) =
852
- let jArray = value :?> obj list
853
- let factors = jArray |> List.map (string >> int)
854
- sprintf "(%A, %A)" factors.[0] factors.[1]
766
+ let toFactors (value: JToken) =
767
+ sprintf "(%s, %s)" (string value.[0]) (string value.[1])
855
768
 
856
- let toPalindromeProducts (value: obj) =
857
- let jObject = value :?> JObject
858
- let palindromeValue = jObject.Value<int>("value")
769
+ let toPalindromeProducts (value: JToken) =
770
+ let palindromeValue = value.Value<int>("value")
859
771
  let factors =
860
- jObject.Value<JArray>("factors")
861
- |> normalizeJArray
862
- |> Seq.map toFactors
863
- |> formatList
772
+ value.SelectToken("factors")
773
+ |> List.mapRender toFactors
864
774
 
865
775
  sprintf "(%d, %s)" palindromeValue factors
866
776
 
867
777
  override __.RenderExpected (_, _, value) =
868
778
  value
869
- |> Option.ofNonError
870
- |> Option.map toPalindromeProducts
871
- |> formatOption
872
- |> parenthesizeOption
779
+ |> Option.ofNonErrorObject
780
+ |> Option.map toPalindromeProducts
781
+ |> Option.renderStringParenthesized
873
782
 
874
783
  override __.PropertiesUsedAsSutParameter _ = ["min"; "max"]
875
784
 
@@ -879,23 +788,20 @@ type PascalsTriangle() =
879
788
  override __.PropertiesWithIdentifier _ = ["expected"]
880
789
 
881
790
  override __.RenderExpected (_, _, value) =
882
- match value with
883
- | :? JArray ->
884
- let formattedList =
885
- value :?> JArray
886
- |> Seq.map formatValue
887
- |> formatMultiLineList
791
+ match value.Type with
792
+ | JTokenType.Array ->
793
+ let formattedList = List.renderMultiLine value
888
794
 
889
795
  if (formattedList.Contains("\n")) then
890
- sprintf "%s\n%s" formattedList (indent 2 "|> Some")
796
+ sprintf "%s\n%s" formattedList (String.indent 2 "|> Some")
891
797
  else
892
798
  sprintf "%s |> Some" formattedList
893
799
  | _ -> "None"
894
800
 
895
801
  override __.IdentifierTypeAnnotation (canonicalDataCase, key, value) =
896
- match key, value with
897
- | "expected", :? JArray ->
898
- match value :?> JArray |> Seq.isEmpty with
802
+ match key, value.Type with
803
+ | "expected", JTokenType.Array ->
804
+ match Seq.isEmpty value with
899
805
  | true -> Some "int list list option"
900
806
  | false -> None
901
807
  | _ -> base.IdentifierTypeAnnotation (canonicalDataCase, key, value)
@@ -905,23 +811,21 @@ type PascalsTriangle() =
905
811
  type PerfectNumbers() =
906
812
  inherit GeneratorExercise()
907
813
 
908
- let toClassification value = string value |> String.dehumanize
814
+ let toClassification value = Obj.renderEnum "Classification" value
909
815
 
910
816
  override __.RenderExpected (_, _, value) =
911
- value
912
- |> Option.ofNonError
913
- |> Option.map toClassification
914
- |> formatOption
915
- |> parenthesizeOption
817
+ value
818
+ |> Option.ofNonErrorObject
819
+ |> Option.map toClassification
820
+ |> Option.renderStringParenthesized
916
821
 
917
822
  type PhoneNumber() =
918
823
  inherit GeneratorExercise()
919
824
 
920
825
  override __.RenderExpected (_, _, value) =
921
826
  value
922
- |> Option.ofObj
923
- |> formatValue
924
- |> parenthesizeOption
827
+ |> Option.ofNonNull
828
+ |> Option.renderParenthesized
925
829
 
926
830
  type PigLatin() =
927
831
  inherit GeneratorExercise()
@@ -934,7 +838,7 @@ type Poker() =
934
838
  type Pov() =
935
839
  inherit GeneratorExercise()
936
840
 
937
- let isNull x = match x with null -> true | _ -> false
841
+ let isNull (jToken: JToken) = jToken.Type = JTokenType.Null
938
842
 
939
843
  override __.RenderSetup _ =
940
844
  ["let rec graphToList (graph: Graph<'a>) = "
@@ -946,21 +850,17 @@ type Pov() =
946
850
  "let mapToList graph = match graph with | Some x -> graphToList x | None -> []"
947
851
  ] |> String.concat "\n"
948
852
 
949
- member this.RenderNode (tree: obj) : string =
853
+ member this.RenderNode (tree: JToken) : string =
950
854
  match isNull tree with
951
855
  | true -> ""
952
856
  | false ->
953
- let node = (tree :?> JObject).ToObject<Collections.Generic.Dictionary<string, JToken>>();
857
+ let node = tree.ToObject<Collections.Generic.Dictionary<string, JToken>>()
954
858
  let children =
955
- if node.ContainsKey "children" then
956
- node.["children"]
957
- |> Seq.map this.RenderNode
958
- |> formatList
859
+ if node.ContainsKey "children" then
860
+ List.mapRender this.RenderNode node.["children"]
959
861
  else
960
862
  "[]"
961
- let label =
962
- node.["label"]
963
- |> formatValue
863
+ let label = Obj.render node.["label"]
964
864
  sprintf "mkGraph %s %s" label children
965
865
 
966
866
  override this.RenderArrange canonicalDataCase =
@@ -983,19 +883,13 @@ type Pov() =
983
883
  override __.RenderSut canonicalDataCase =
984
884
  match canonicalDataCase.Property with
985
885
  | "fromPov" ->
986
- let from =
987
- canonicalDataCase.Input.["from"]
988
- |> formatValue
886
+ let from = Obj.render canonicalDataCase.Input.["from"]
989
887
  match isNull canonicalDataCase.Expected with
990
888
  | false -> sprintf "fromPOV %s tree |> mapToList " from
991
889
  | true -> sprintf "fromPOV %s tree " from
992
890
  | "pathTo" ->
993
- let fromValue =
994
- canonicalDataCase.Input.["from"]
995
- |> formatValue
996
- let toValue =
997
- canonicalDataCase.Input.["to"]
998
- |> formatValue
891
+ let fromValue = Obj.render canonicalDataCase.Input.["from"]
892
+ let toValue = Obj.render canonicalDataCase.Input.["to"]
999
893
  sprintf "tracePathBetween %s %s tree" fromValue toValue
1000
894
  | _ -> ""
1001
895
 
@@ -1009,10 +903,8 @@ type Pov() =
1009
903
  match isNull value with
1010
904
  | true -> "None"
1011
905
  | false ->
1012
- printf "%s" canonicalDataCase.Description
1013
- canonicalDataCase.Expected :?> JArray
1014
- |> Seq.map formatValue
1015
- |> formatList
906
+ canonicalDataCase.Expected
907
+ |> List.render
1016
908
  |> sprintf "<| Some %s"
1017
909
  | _ -> ""
1018
910
 
@@ -1030,13 +922,10 @@ type Proverb() =
1030
922
 
1031
923
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
1032
924
 
1033
- override __.RenderExpected (_, _, value) =
1034
- value :?> JArray
1035
- |> Seq.map formatValue
1036
- |> formatMultiLineList
925
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
1037
926
 
1038
927
  override __.IdentifierTypeAnnotation (_, _, value) =
1039
- match value :?> JArray |> Seq.isEmpty with
928
+ match Seq.isEmpty value with
1040
929
  | true -> Some "string list"
1041
930
  | false -> None
1042
931
 
@@ -1045,16 +934,14 @@ type QueenAttack() =
1045
934
 
1046
935
  override __.RenderExpected (canonicalDataCase, key, value) =
1047
936
  match canonicalDataCase.Property with
1048
- | "create" -> value :?> int64 <> -1L |> formatValue
937
+ | "create" -> value.ToObject<int>() <> -1 |> Obj.render
1049
938
  | _ -> base.RenderExpected (canonicalDataCase, key, value)
1050
939
 
1051
940
  override __.RenderInput (canonicalDataCase, key, value) =
1052
- let parsePositionTuple (tupleValue: obj) =
1053
- let position = (tupleValue :?> JToken).SelectToken("position")
1054
- formatValue (position.["row"].ToObject<int>(), position.["column"].ToObject<int>())
1055
-
1056
941
  match key with
1057
- | "queen" | "white_queen" | "black_queen" -> parsePositionTuple value
942
+ | "queen" | "white_queen" | "black_queen" ->
943
+ let position = value.SelectToken("position")
944
+ Obj.render (position.["row"].ToObject<int>(), position.["column"].ToObject<int>())
1058
945
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1059
946
 
1060
947
  override __.PropertiesWithIdentifier _ = ["white_queen"; "black_queen"]
@@ -1073,13 +960,13 @@ type RationalNumbers() =
1073
960
  inherit GeneratorExercise()
1074
961
 
1075
962
  override __.RenderValue (canonicalDataCase, key, value) =
1076
- match value with
1077
- | :? JArray as jArray -> sprintf "(create %d %d)" (jArray.[0].Value<int>()) (jArray.[1].Value<int>())
963
+ match value.Type with
964
+ | JTokenType.Array -> sprintf "(create %d %d)" (value.[0].Value<int>()) (value.[1].Value<int>())
1078
965
  | _ -> base.RenderValue (canonicalDataCase, key, value)
1079
966
 
1080
967
  override __.AssertTemplate canonicalDataCase =
1081
- match canonicalDataCase.Expected with
1082
- | :? double -> "AssertEqualWithin"
968
+ match canonicalDataCase.Expected.Type with
969
+ | JTokenType.Float -> "AssertEqualWithin"
1083
970
  | _ -> base.AssertTemplate(canonicalDataCase)
1084
971
 
1085
972
  type React() =
@@ -1088,27 +975,26 @@ type React() =
1088
975
  let renderCells canonicalDataCase =
1089
976
  let reactorVar = sprintf "let %s = new %s()" "reactor" "Reactor"
1090
977
  let cellVars =
1091
- canonicalDataCase.Input.["cells"] :?> JArray
978
+ canonicalDataCase.Input.["cells"]
1092
979
  |> Seq.map (fun (cellValue: JToken) ->
1093
- let cell = cellValue :?> JObject
1094
- let cellName = cell.["name"].ToObject<string>()
1095
- match cell.["type"].ToObject<string>() with
980
+ let cellName = cellValue.["name"].ToObject<string>()
981
+ match cellValue.["type"].ToObject<string>() with
1096
982
  | "compute" ->
1097
983
  let funBody =
1098
- cell.["compute_function"].ToObject<string>().Replace ("inputs", "values.")
984
+ cellValue.["compute_function"].ToObject<string>().Replace ("inputs", "values.")
1099
985
  let inputParams =
1100
- (cell.["inputs"].ToObject<seq<string>>() |> formatList)
986
+ (cellValue.["inputs"].ToObject<string list>() |> List.mapRender id)
1101
987
 
1102
988
  sprintf "let %s = reactor.createComputeCell %s (fun values -> %s)" cellName inputParams funBody
1103
989
  | "input" ->
1104
- let initialValue = cell.["initial_value"].ToObject<int64>()
1105
- sprintf "let %s = reactor.createInputCell %s" cellName (formatValue initialValue)
990
+ let initialValue = cellValue.["initial_value"].ToObject<int>()
991
+ sprintf "let %s = reactor.createInputCell %s" cellName (Obj.render initialValue)
1106
992
  | _ -> ""
1107
993
  )
1108
994
  |> Seq.toList
1109
995
  [ reactorVar ] @ cellVars
1110
996
 
1111
- let renderExpectedCellValueOperation (op: JObject) =
997
+ let renderExpectedCellValueOperation (op: JToken) =
1112
998
  seq {
1113
999
  let cellName = op.["cell"].ToObject<string>()
1114
1000
  let expectedValue = op.["value"].ToObject<int>()
@@ -1132,13 +1018,13 @@ type React() =
1132
1018
  | _ -> Seq.empty
1133
1019
 
1134
1020
  let renderExpectedCallbacksNotToBeCalled (jToken: JToken) =
1135
- match jToken with
1136
- | :? JArray as jArray ->
1137
- jArray.ToObject<string list>()
1021
+ if not (isNull jToken) && jToken.Type = JTokenType.Array then
1022
+ jToken.ToObject<string list>()
1138
1023
  |> Seq.map (sprintf "A.CallTo(fun() -> %sHandler.Invoke(A<obj>.``_``, A<int>.``_``)).MustNotHaveHappened() |> ignore")
1139
- | _ -> Seq.empty
1024
+ else
1025
+ Seq.empty
1140
1026
 
1141
- let renderSetValueOperation (op: JObject) =
1027
+ let renderSetValueOperation (op: JToken) =
1142
1028
  seq {
1143
1029
  let cellName = op.["cell"].ToObject<string>()
1144
1030
  let cellValue = op.["value"].ToObject<int>()
@@ -1147,7 +1033,7 @@ type React() =
1147
1033
  yield! renderExpectedCallbacksNotToBeCalled op.["expect_callbacks_not_to_be_called"]
1148
1034
  }
1149
1035
 
1150
- let renderAddCallbackOperation (op: JObject) =
1036
+ let renderAddCallbackOperation (op: JToken) =
1151
1037
  seq {
1152
1038
  let callbackName = op.["name"].ToObject<string>()
1153
1039
  let cellName = op.["cell"].ToObject<string>()
@@ -1156,14 +1042,14 @@ type React() =
1156
1042
  yield sprintf "%s.Changed.AddHandler %s" cellName callbackHandlerName
1157
1043
  }
1158
1044
 
1159
- let renderRemoveCallbackOperation (op: JObject) =
1045
+ let renderRemoveCallbackOperation (op: JToken) =
1160
1046
  seq {
1161
1047
  let cellName = op.["cell"].ToObject<string>()
1162
1048
  let callbackName = op.["name"].ToObject<string>()
1163
1049
  yield sprintf "%s.Changed.RemoveHandler %sHandler" cellName callbackName
1164
1050
  }
1165
1051
 
1166
- let renderOperation (op: JObject) =
1052
+ let renderOperation (op: JToken) =
1167
1053
  let opType = op.["type"].ToObject<string>()
1168
1054
  match opType with
1169
1055
  | "expect_cell_value" -> renderExpectedCellValueOperation op
@@ -1173,8 +1059,7 @@ type React() =
1173
1059
  | _ -> failwith "Unknown operation type"
1174
1060
 
1175
1061
  let renderOperations canonicalDataCase =
1176
- canonicalDataCase.Input.["operations"] :?> JArray
1177
- |> Seq.cast<JObject>
1062
+ canonicalDataCase.Input.["operations"]
1178
1063
  |> Seq.collect renderOperation
1179
1064
  |> Seq.toList
1180
1065
 
@@ -1194,11 +1079,7 @@ type Rectangles() =
1194
1079
 
1195
1080
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
1196
1081
 
1197
- override __.RenderInput (_, _, value) =
1198
- value :?> JArray
1199
- |> normalizeJArray
1200
- |> Seq.map formatValue
1201
- |> formatMultiLineList
1082
+ override __.RenderInput (_, _, value) = List.renderMultiLine value
1202
1083
 
1203
1084
  type ReverseString() =
1204
1085
  inherit GeneratorExercise()
@@ -1206,18 +1087,15 @@ type ReverseString() =
1206
1087
  type RobotSimulator() =
1207
1088
  inherit GeneratorExercise()
1208
1089
 
1209
- let parseInput (input: obj) =
1210
- let token = input :?> JToken
1090
+ let parseInput (token: JToken) =
1211
1091
  let direction = token.SelectToken "direction" |> Option.ofObj
1212
1092
  let position = token.SelectToken "position" |> Option.ofObj
1213
1093
  (direction, position)
1214
1094
 
1215
- let renderDirection (value: JToken) =
1216
- value.ToObject<string>() |> String.upperCaseFirst
1095
+ let renderDirection (value: JToken) = Obj.renderEnum "Direction" value
1217
1096
 
1218
1097
  let renderPosition (position: JToken) =
1219
- (position.["x"].ToObject<int>(), position.["y"].ToObject<int>())
1220
- |> formatValue
1098
+ Obj.render (position.["x"].ToObject<int>(), position.["y"].ToObject<int>())
1221
1099
 
1222
1100
  let renderRobot direction position =
1223
1101
  sprintf "create %s %s" (renderDirection direction) (renderPosition position)
@@ -1258,7 +1136,7 @@ type RobotSimulator() =
1258
1136
  match canonicalDataCase.Property with
1259
1137
  | "create" -> "robot"
1260
1138
  | "turnLeft" | "turnRight" | "advance" -> sprintf "%s robot" canonicalDataCase.Property
1261
- | "instructions" -> sprintf "instructions %s robot" (formatValue canonicalDataCase.Input.["instructions"])
1139
+ | "instructions" -> sprintf "instructions %s robot" (Obj.render canonicalDataCase.Input.["instructions"])
1262
1140
  | _ -> base.RenderSut canonicalDataCase
1263
1141
 
1264
1142
  override __.TestMethodName canonicalDataCase =
@@ -1274,9 +1152,6 @@ type RotationalCipher() =
1274
1152
  type RnaTranscription() =
1275
1153
  inherit GeneratorExercise()
1276
1154
 
1277
- override __.RenderExpected (_, _, value) =
1278
- value |> Option.ofObj |> formatValue |> parenthesizeOption
1279
-
1280
1155
  type RunLengthEncoding() =
1281
1156
  inherit GeneratorExercise()
1282
1157
 
@@ -1301,19 +1176,12 @@ type RomanNumerals() =
1301
1176
  type SaddlePoints() =
1302
1177
  inherit GeneratorExercise()
1303
1178
 
1304
- let renderSaddlePoint (input: JObject) =
1305
- (input.Value<int>("row"), input.Value<int>("column")) |> formatTuple
1179
+ let renderSaddlePoint (input: JToken) =
1180
+ Obj.render (input.Value<int>("row"), input.Value<int>("column"))
1306
1181
 
1307
- override __.RenderInput (_, _, value) =
1308
- value :?> JArray
1309
- |> normalizeJArray
1310
- |> Seq.map formatValue
1311
- |> formatMultiLineList
1182
+ override __.RenderInput (_, _, value) = List.renderMultiLine value
1312
1183
 
1313
- override __.RenderExpected (_, _, value) =
1314
- (value :?> JArray).Values<JObject>()
1315
- |> Seq.map renderSaddlePoint
1316
- |> formatList
1184
+ override __.RenderExpected (_, _, value) = List.mapRender renderSaddlePoint value
1317
1185
 
1318
1186
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
1319
1187
 
@@ -1322,9 +1190,8 @@ type Say() =
1322
1190
 
1323
1191
  override __.RenderExpected (_, _, value) =
1324
1192
  value
1325
- |> Option.ofPositiveInt
1326
- |> formatValue
1327
- |> parenthesizeOption
1193
+ |> Option.ofNonNegativeNumber
1194
+ |> Option.renderParenthesized
1328
1195
 
1329
1196
  override __.RenderInput (_, _, value) = sprintf "%sL" (string value)
1330
1197
 
@@ -1339,7 +1206,10 @@ type ScaleGenerator() =
1339
1206
 
1340
1207
  override __.RenderInput (canonicalDataCase, key, value) =
1341
1208
  match key with
1342
- | "intervals" -> value |> Option.ofObj |> formatValue |> parenthesizeOption
1209
+ | "intervals" ->
1210
+ value
1211
+ |> Option.ofObj
1212
+ |> Option.renderParenthesized
1343
1213
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1344
1214
 
1345
1215
  override __.PropertiesUsedAsSutParameter _ = ["tonic"; "intervals"]
@@ -1350,12 +1220,6 @@ type ScrabbleScore() =
1350
1220
  type Sieve() =
1351
1221
  inherit GeneratorExercise()
1352
1222
 
1353
- override __.RenderExpected (_, _, value) =
1354
- (value :?> JArray)
1355
- |> normalizeJArray
1356
- |> Seq.map formatValue
1357
- |> formatList
1358
-
1359
1223
  type SecretHandshake() =
1360
1224
  inherit GeneratorExercise()
1361
1225
 
@@ -1363,30 +1227,28 @@ type Series() =
1363
1227
  inherit GeneratorExercise()
1364
1228
 
1365
1229
  override __.RenderExpected (_, _, value) =
1366
- value |> Option.ofNonError |> formatValue |> parenthesizeOption
1230
+ value
1231
+ |> Option.ofNonErrorObject
1232
+ |> Option.renderParenthesized
1367
1233
 
1368
1234
  type SpaceAge() =
1369
1235
  inherit GeneratorExercise()
1370
1236
 
1371
1237
  override __.RenderInput (canonicalDataCase, key, value) =
1372
- match value with
1373
- | :? string as s -> s
1374
- | :? int64 as i -> sprintf "%dL" i
1238
+ match value.Type with
1239
+ | JTokenType.String -> value.ToObject<string>()
1240
+ | JTokenType.Integer -> sprintf "%dL" (value.ToObject<int64>())
1375
1241
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1376
1242
 
1377
1243
  type SpiralMatrix() =
1378
1244
  inherit GeneratorExercise()
1379
1245
 
1380
- override __.RenderExpected (_, _, value) =
1381
- value :?> JArray
1382
- |> Seq.map formatValue
1383
- |> formatMultiLineList
1246
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
1384
1247
 
1385
1248
  type Sublist() =
1386
1249
  inherit GeneratorExercise()
1387
1250
 
1388
- override __.RenderExpected (_, _, value) =
1389
- string value |> String.upperCaseFirst
1251
+ override __.RenderExpected (_, _, value) = Obj.renderEnum "SublistType" value
1390
1252
 
1391
1253
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
1392
1254
 
@@ -1398,10 +1260,7 @@ type Tournament() =
1398
1260
 
1399
1261
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
1400
1262
 
1401
- override __.RenderValue (_, _, value) =
1402
- value :?> JArray
1403
- |> Seq.map formatValue
1404
- |> formatMultiLineList
1263
+ override __.RenderValue (_, _, value) = List.renderMultiLine value
1405
1264
 
1406
1265
  type TwelveDays() =
1407
1266
  inherit GeneratorExercise()
@@ -1410,10 +1269,7 @@ type TwelveDays() =
1410
1269
 
1411
1270
  override __.PropertiesWithIdentifier _ = ["expected"]
1412
1271
 
1413
- override __.RenderExpected (_, _, value) =
1414
- value :?> JArray
1415
- |> Seq.map formatValue
1416
- |> formatMultiLineList
1272
+ override __.RenderExpected (_, _, value) = List.renderMultiLine value
1417
1273
 
1418
1274
  type Transpose() =
1419
1275
  inherit GeneratorExercise()
@@ -1421,24 +1277,17 @@ type Transpose() =
1421
1277
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
1422
1278
 
1423
1279
  override __.IdentifierTypeAnnotation (_, _, value) =
1424
- match value :?> JArray |> Seq.isEmpty with
1280
+ match Seq.isEmpty value with
1425
1281
  | true -> Some "string list"
1426
1282
  | false -> None
1427
1283
 
1428
- override __.RenderValue (_, _, value) =
1429
- value :?> JArray
1430
- |> Seq.map formatValue
1431
- |> formatMultiLineList
1284
+ override __.RenderValue (_, _, value) = List.renderMultiLine value
1432
1285
 
1433
1286
  type Triangle() =
1434
1287
  inherit GeneratorExercise()
1435
1288
 
1436
- let formatFloat (value:obj) =
1437
- match value with
1438
- | :? int64 as i -> sprintf "%.1f" (float i)
1439
- | :? int32 as i -> sprintf "%.1f" (float i)
1440
- | :? float as f -> sprintf "%.1f" f
1441
- | _ -> failwith "Invalid value"
1289
+ let formatFloat (jToken: JToken) =
1290
+ sprintf "%.1f" (jToken.ToObject<float>())
1442
1291
 
1443
1292
  let hasUniqueTestMethodName canonicalDataCase =
1444
1293
  canonicalDataCase.Description.Contains "equilateral" ||
@@ -1450,17 +1299,12 @@ type Triangle() =
1450
1299
  | true -> base.TestMethodName canonicalDataCase
1451
1300
  | false -> sprintf "%s returns %s" (String.upperCaseFirst canonicalDataCase.Property) canonicalDataCase.Description
1452
1301
 
1453
- override __.RenderInput (_, _, value) =
1454
- value :?> JArray
1455
- |> normalizeJArray
1456
- |> Seq.map formatFloat
1457
- |> formatList
1302
+ override __.RenderInput (_, _, value) = List.mapRender formatFloat value
1458
1303
 
1459
1304
  type TwoBucket() =
1460
1305
  inherit GeneratorExercise()
1461
1306
 
1462
- let renderBucket (value: obj) =
1463
- value |> string |> String.upperCaseFirst |> sprintf "Bucket.%s"
1307
+ let renderBucket (value: JToken) = Obj.renderEnum "Bucket" value
1464
1308
 
1465
1309
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
1466
1310
 
@@ -1470,94 +1314,72 @@ type TwoBucket() =
1470
1314
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1471
1315
 
1472
1316
  override __.RenderExpected (_, _, value) =
1473
- let jObject = value :?> JObject
1474
- let moves = jObject.Value<int>("moves")
1475
- let goalBucket = jObject.Value<string>("goalBucket") |> renderBucket
1476
- let otherBucket = jObject.Value<int>("otherBucket")
1317
+ let moves = value.["moves"].ToObject<int>()
1318
+ let goalBucket = renderBucket value.["goalBucket"]
1319
+ let otherBucket = value.["otherBucket"].ToObject<int>()
1477
1320
  sprintf "{ Moves = %d; GoalBucket = %s; OtherBucket = %d }" moves goalBucket otherBucket
1478
1321
 
1479
1322
  type TwoFer() =
1480
1323
  inherit GeneratorExercise()
1481
1324
 
1482
1325
  override __.RenderInput (_, _, value) =
1483
- value |> Option.ofObj |> formatValue |> parenthesizeOption
1326
+ value
1327
+ |> Option.ofNonNull
1328
+ |> Option.renderParenthesized
1484
1329
 
1485
1330
  type VariableLengthQuantity() =
1486
1331
  inherit GeneratorExercise()
1487
1332
 
1488
- let formatUnsignedByteList (value: obj) =
1489
- value :?> JArray
1490
- |> Seq.map (fun x -> x.Value<byte>() |> sprintf "0x%xuy")
1491
- |> formatList
1333
+ let formatUnsignedByteList (value: JToken) =
1334
+ value.ToObject<byte list>()
1335
+ |> List.mapRender (sprintf "0x%xuy")
1492
1336
 
1493
- let formatUnsignedIntList (value: obj) =
1494
- value :?> JArray
1495
- |> Seq.map (fun x -> x.Value<uint32>() |> sprintf "0x%xu")
1496
- |> formatList
1337
+ let formatUnsignedIntList (value: JToken) =
1338
+ value.ToObject<uint32 list>()
1339
+ |> List.mapRender (sprintf "0x%xu")
1497
1340
 
1498
1341
  override __.RenderInput (canonicalDataCase, key, value) =
1499
1342
  match canonicalDataCase.Property with
1500
- | "encode" -> value |> formatUnsignedIntList
1501
- | "decode" -> value |> formatUnsignedByteList
1343
+ | "encode" -> formatUnsignedIntList value
1344
+ | "decode" -> formatUnsignedByteList value
1502
1345
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1503
1346
 
1504
1347
  override __.RenderExpected (canonicalDataCase, key, value) =
1505
1348
  match canonicalDataCase.Property with
1506
- | "encode" -> value |> formatUnsignedByteList
1507
- | "decode" -> value |> Option.ofObj |> Option.map formatUnsignedIntList |> formatOption |> parenthesizeOption
1349
+ | "encode" -> formatUnsignedByteList value
1350
+ | "decode" ->
1351
+ value
1352
+ |> Option.ofNonNull
1353
+ |> Option.map formatUnsignedIntList
1354
+ |> Option.renderStringParenthesized
1508
1355
  | _ -> base.RenderExpected (canonicalDataCase, key, value)
1509
1356
 
1510
1357
  type WordCount() =
1511
1358
  inherit GeneratorExercise()
1512
- member __.FormatMap<'TKey, 'TValue> (value: obj) =
1513
- let input = value :?> JObject
1514
- let dict = input.ToObject<Collections.Generic.Dictionary<'TKey, 'TValue>>();
1515
- let formattedList =
1516
- dict
1517
- |> Seq.map (fun kv -> formatTuple (kv.Key, kv.Value))
1518
- |> formatMultiLineList
1519
-
1520
- if (formattedList.Contains("\n")) then
1521
- sprintf "%s\n%s" formattedList (indent 2 "|> Map.ofList")
1522
- else
1523
- sprintf "%s |> Map.ofList" formattedList
1524
1359
 
1525
- override this.RenderExpected (_, _, value) = this.FormatMap<string, int> value
1360
+ override __.RenderExpected (_, _, value) = Map.render<string, int> value
1526
1361
 
1527
1362
  override __.PropertiesWithIdentifier _ = ["expected"]
1528
1363
 
1529
1364
  type WordSearch() =
1530
1365
  inherit GeneratorExercise()
1531
1366
 
1532
- let toCoordinates (value: JToken) = value.Value<int>("column"), value.Value<int>("row")
1367
+ let toCoordinates (value: JToken) = (value.Value<int>("column"), value.Value<int>("row"))
1533
1368
 
1534
1369
  let renderExpectedCoordinates (value: JObject) =
1535
- formatTuple (value.Item("start") |> toCoordinates, value.Item("end") |> toCoordinates)
1370
+ Obj.render (value.Item("start") |> toCoordinates, value.Item("end") |> toCoordinates)
1536
1371
 
1537
1372
  let renderExpectedValue (value: JObject) =
1538
1373
  match isNull value with
1539
1374
  | true -> "Option<((int * int) * (int * int))>.None"
1540
- | false -> sprintf "Some (%s)" (renderExpectedCoordinates value)
1375
+ | false -> renderExpectedCoordinates value |> Some |> Option.renderString
1541
1376
 
1542
1377
  override __.RenderExpected (_, _, value) =
1543
- let input = value :?> JObject
1544
- let formattedList =
1545
- input.ToObject<Collections.Generic.Dictionary<string, JObject>>()
1546
- |> Seq.map (fun kv -> sprintf "(%s, %s)" (formatValue kv.Key) (renderExpectedValue kv.Value))
1547
- |> formatMultiLineList
1548
-
1549
- if (formattedList.Contains("\n")) then
1550
- sprintf "%s\n%s" formattedList (indent 2 "|> Map.ofList")
1551
- else
1552
- sprintf "%s |> Map.ofList" formattedList
1378
+ Map.mapRender (fun kv -> sprintf "(%s, %s)" (Obj.render kv.Key) (renderExpectedValue kv.Value)) value
1553
1379
 
1554
1380
  override __.RenderInput (canonicalDataCase, key, value) =
1555
1381
  match key with
1556
- | "grid" ->
1557
- value :?> JArray
1558
- |> normalizeJArray
1559
- |> Seq.map formatValue
1560
- |> formatMultiLineList
1382
+ | "grid" -> List.renderMultiLine value
1561
1383
  | _ ->
1562
1384
  base.RenderInput(canonicalDataCase, key, value)
1563
1385
 
@@ -1567,14 +1389,16 @@ type Wordy() =
1567
1389
  inherit GeneratorExercise()
1568
1390
 
1569
1391
  override __.RenderExpected (_, _, value) =
1570
- value |> Option.ofNonFalse |> formatValue |> parenthesizeOption
1392
+ value
1393
+ |> Option.ofNonFalseBoolean
1394
+ |> Option.renderParenthesized
1571
1395
 
1572
1396
  type Yacht() =
1573
1397
  inherit GeneratorExercise()
1574
1398
 
1575
1399
  override __.RenderInput (canonicalDataCase, key, value) =
1576
1400
  match key with
1577
- | "category" -> sprintf "Category.%s" (value |> string |> String.dehumanize)
1401
+ | "category" -> Obj.renderEnum "Category" value
1578
1402
  | _ -> base.RenderInput (canonicalDataCase, key, value)
1579
1403
 
1580
1404
  type ZebraPuzzle() =
@@ -1617,52 +1441,54 @@ type Zipper() =
1617
1441
  | "setValue" ->
1618
1442
  [sprintf "setValue %s" (jToken.["item"] |> string)]
1619
1443
  | "setLeft"| "setRight" ->
1620
- match jToken.["item"] with
1621
- | :? JObject as subTree ->
1622
- let tree = renderTree true subTree
1623
- [sprintf "%s (Some (%s))" operation tree]
1624
- | _ ->
1625
- [sprintf "%s None" operation]
1444
+ let expected =
1445
+ match jToken.["item"] with
1446
+ | :? JObject as subTree ->
1447
+ Some (renderTree true subTree |> String.parenthesize)
1448
+ | _ ->
1449
+ None
1450
+
1451
+ [sprintf "%s %s" operation (Option.renderStringParenthesized expected)]
1626
1452
  | _ -> failwith "Unknown operation"
1627
1453
 
1628
- let renderOperations (operations: JArray) =
1454
+ let renderOperations (operations: JToken) =
1629
1455
  operations
1630
1456
  |> Seq.mapi (renderOperation (Seq.length operations))
1631
1457
  |> Seq.concat
1632
1458
  |> String.concat " |> "
1633
1459
  |> sprintf "|> %s"
1634
1460
 
1635
- let renderTreeWithIdentifier identifier (tree: JObject) =
1461
+ let renderTreeWithIdentifier identifier (tree: JToken) =
1636
1462
  tree
1637
1463
  |> renderTree true
1638
1464
  |> sprintf "let %s = %s" identifier
1639
1465
 
1640
- let renderZipperWithIdentifier identifier (tree: JObject) =
1466
+ let renderZipperWithIdentifier identifier (tree: JToken) =
1641
1467
  let renderedTree = renderTree true tree
1642
1468
  sprintf "let %s = fromTree (%s)" identifier renderedTree
1643
1469
 
1644
- let renderExpectedZipperWithIdentifier identifier (tree: JObject) (operations: JArray) =
1470
+ let renderExpectedZipperWithIdentifier identifier (tree: JToken) (operations: JToken) =
1645
1471
  let renderedTree = renderTree true tree
1646
1472
  let renderedOperations = renderOperations operations
1647
1473
  sprintf "let %s = fromTree (%s) %s" identifier renderedTree renderedOperations
1648
1474
 
1649
- let renderSut (operations: JArray) =
1475
+ let renderSut (operations: JToken) =
1650
1476
  operations
1651
1477
  |> renderOperations
1652
1478
  |> sprintf "let sut = zipper %s"
1653
1479
 
1654
- let renderExpected (expected: JObject) =
1480
+ let renderExpected (expected: JToken) =
1655
1481
  match expected.["type"] |> string with
1656
1482
  | "int" ->
1657
1483
  expected.["value"] |> string |> sprintf "let expected = %s"
1658
1484
  | "zipper" ->
1659
1485
  match expected.["initialTree"] with
1660
1486
  | :? JObject as jObject ->
1661
- renderExpectedZipperWithIdentifier "expected" jObject (expected.["operations"] :?> JArray)
1487
+ renderExpectedZipperWithIdentifier "expected" jObject expected.["operations"]
1662
1488
  | _ ->
1663
1489
  "let expected = None"
1664
1490
  | "tree" ->
1665
- expected.["value"] :?> JObject |> renderTreeWithIdentifier "expected"
1491
+ expected.["value"] |> renderTreeWithIdentifier "expected"
1666
1492
  | _ -> failwith "Unknown expected type"
1667
1493
 
1668
1494
  override __.RenderSetup _ =
@@ -1673,9 +1499,9 @@ type Zipper() =
1673
1499
  override __.PropertiesWithIdentifier _ = ["initialTree"; "sut"; "expected"]
1674
1500
 
1675
1501
  override __.RenderArrange canonicalDataCase =
1676
- let tree = canonicalDataCase.Input.["initialTree"] :?> JObject |> renderZipperWithIdentifier "zipper"
1677
- let sut = canonicalDataCase.Input.["operations"] :?> JArray |> renderSut
1678
- let expected = canonicalDataCase.Expected :?> JObject |> renderExpected
1502
+ let tree = canonicalDataCase.Input.["initialTree"] |> renderZipperWithIdentifier "zipper"
1503
+ let sut = canonicalDataCase.Input.["operations"] |> renderSut
1504
+ let expected = canonicalDataCase.Expected |> renderExpected
1679
1505
  [tree; sut; expected]
1680
1506
 
1681
1507
  override __.TestMethodName canonicalDataCase =