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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/crypto-square/description.md +23 -19
- data/problem-specifications/exercises/yacht/canonical-data.json +10 -1
- data/tracks/clojure/exercises/gigasecond/src/gigasecond.clj +5 -0
- data/tracks/clojure/exercises/grade-school/src/grade_school.clj +13 -0
- data/tracks/clojure/exercises/grains/src/grains.clj +9 -0
- data/tracks/clojure/exercises/minesweeper/src/minesweeper.clj +5 -0
- data/tracks/fsharp/docs/GENERATORS.md +12 -14
- data/tracks/fsharp/exercises/bowling/BowlingTest.fs +15 -15
- data/tracks/fsharp/exercises/perfect-numbers/PerfectNumbersTest.fs +11 -11
- data/tracks/fsharp/exercises/rna-transcription/Example.fs +7 -15
- data/tracks/fsharp/exercises/rna-transcription/RnaTranscription.fs +1 -1
- data/tracks/fsharp/exercises/rna-transcription/RnaTranscriptionTest.fs +5 -5
- data/tracks/fsharp/exercises/robot-simulator/RobotSimulatorTest.fs +34 -34
- data/tracks/fsharp/exercises/sublist/Example.fs +1 -1
- data/tracks/fsharp/exercises/sublist/Sublist.fs +1 -1
- data/tracks/fsharp/exercises/sublist/SublistTest.fs +17 -17
- data/tracks/fsharp/exercises/word-search/WordSearchTest.fs +56 -57
- data/tracks/fsharp/generators/CanonicalData.fs +14 -15
- data/tracks/fsharp/generators/Common.fs +4 -84
- data/tracks/fsharp/generators/Conversion.fs +75 -0
- data/tracks/fsharp/generators/Exercise.fs +15 -11
- data/tracks/fsharp/generators/Generators.fs +294 -468
- data/tracks/fsharp/generators/Generators.fsproj +2 -1
- data/tracks/fsharp/generators/Rendering.fs +169 -61
- data/tracks/fsharp/generators/Templates.fs +64 -0
- data/tracks/fsharp/generators/Track.fs +3 -3
- data/tracks/idris/exercises/accumulate/src/Example.idr +1 -1
- data/tracks/idris/exercises/accumulate/src/Test/Accumulate.idr +2 -2
- data/tracks/java/exercises/rna-transcription/.meta/hints.md +2 -0
- data/tracks/java/exercises/rna-transcription/README.md +6 -0
- data/tracks/nim/.gitignore +1 -0
- data/tracks/nim/config.json +38 -0
- data/tracks/nim/config/maintainers.json +10 -0
- data/tracks/nim/docs/ABOUT.md +7 -0
- data/tracks/nim/exercises/bob/README.md +2 -0
- data/tracks/nim/exercises/bob/bob_test.nim +31 -13
- data/tracks/nim/exercises/bob/example.nim +2 -2
- data/tracks/nim/exercises/gigasecond/README.md +22 -0
- data/tracks/nim/exercises/gigasecond/example.nim +4 -0
- data/tracks/nim/exercises/gigasecond/gigasecond_test.nim +32 -0
- data/tracks/nim/exercises/isogram/README.md +20 -0
- data/tracks/nim/exercises/isogram/example.nim +6 -0
- data/tracks/nim/exercises/isogram/isogram_test.nim +32 -0
- data/tracks/nim/exercises/space-age/README.md +24 -0
- data/tracks/nim/exercises/space-age/example.nim +17 -0
- data/tracks/nim/exercises/space-age/space_age_test.nim +29 -0
- data/tracks/nim/exercises/triangle/example.nim +22 -22
- data/tracks/nim/exercises/triangle/triangle_test.nim +32 -44
- metadata +19 -3
- 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,
|
14
|
-
Expected:
|
12
|
+
{ Input: Map<string, JToken>
|
13
|
+
Expected: JToken
|
15
14
|
Property: string
|
16
|
-
Properties: Map<string,
|
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
|
-
|
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
|
-
|>
|
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 =
|
80
|
+
let properties = Map.ofJToken jToken
|
82
81
|
|
83
|
-
{ Input =
|
84
|
-
Expected =
|
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 *
|
22
|
-
abstract member RenderInput : CanonicalDataCase * 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 *
|
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 *
|
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
|
-
|
109
|
-
|
110
|
-
|
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) =
|
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
|
-
|
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
|
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.
|
20
|
-
|>
|
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
|
29
|
+
let renderAllergenEnum (jToken: JToken) = Obj.renderEnum "Allergen" jToken
|
28
30
|
|
29
31
|
let renderAllergicToAssert canonicalDataCase (jToken: JToken) =
|
30
|
-
let substance = jToken.["substance"]
|
31
|
-
let score = canonicalDataCase.Input.["score"]
|
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") |>
|
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
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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:
|
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
|
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)
|
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
|
133
|
+
canonicalDataCase.Expected
|
158
134
|
|> renderAssertions ["treeData"]
|
159
135
|
| _ -> base.RenderAssert canonicalDataCase
|
160
136
|
|
161
137
|
override __.RenderInput (_, _, value) =
|
162
|
-
value
|
163
|
-
|>
|
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
|
-
|
|
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
|
-
|
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
|
198
|
-
yield sprintf "let rolls = %s"
|
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"]
|
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
|
-
|
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
|
-
|
219
|
-
|
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"]
|
227
|
-
|
|
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"]
|
244
|
-
let operations =
|
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 =
|
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<
|
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:
|
285
|
-
let
|
286
|
-
let
|
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
|
291
|
-
this.RenderSutParameter (canonicalDataCase,
|
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
|
-
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
[
|
352
|
-
|
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
|
-
|
|
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 =
|
348
|
+
let lines = value.ToObject<string list>()
|
374
349
|
let padSize = List.last lines |> String.length
|
375
350
|
|
376
|
-
lines
|
377
|
-
|>
|
378
|
-
|>
|
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.
|
388
|
-
|>
|
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:
|
402
|
-
|
403
|
-
|>
|
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
|
-
| _ ->
|
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" (
|
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:
|
464
|
-
let items = value
|
465
|
-
|
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
|
-
|
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
|
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.
|
520
|
-
|>
|
473
|
+
|> Option.ofNonNull
|
474
|
+
|> Option.render
|
521
475
|
|
522
476
|
override __.IdentifierTypeAnnotation (_, _, value) =
|
523
|
-
|
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) =
|
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)
|
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
|
551
|
-
(arr.[0]
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
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 (
|
566
|
-
match Option.
|
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 (
|
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 =
|
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,
|
527
|
+
let territoryPosition (input: Map<string, JToken>) =
|
580
528
|
let valueToInt key = input |> Map.find key |> string |> int
|
581
|
-
(valueToInt "x"
|
529
|
+
let position = sprintf "{ \"x\": %d, \"y\": %d }" (valueToInt "x") (valueToInt "y")
|
530
|
+
JToken.Parse(position)
|
582
531
|
|
583
|
-
let mapTerritoryInput (input: Map<string,
|
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
|
-
|
598
|
-
|
599
|
-
|>
|
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.
|
563
|
+
match Option.ofNonErrorObject value with
|
615
564
|
| None -> None
|
616
565
|
| Some _ ->
|
617
|
-
if
|
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
|
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.
|
669
|
-
|>
|
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
|
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.
|
715
|
-
|>
|
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
|
-
|>
|
761
|
-
|> parenthesize
|
704
|
+
|> DateTime.renderParenthesized
|
762
705
|
|
763
706
|
override __.RenderInput (canonicalDataCase, key, value) =
|
764
707
|
match key with
|
765
|
-
| "dayofweek" ->
|
766
|
-
|
767
|
-
|
|
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
|
-
|
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) =
|
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
|
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.
|
801
|
-
|>
|
802
|
-
|> parenthesizeOption
|
735
|
+
|> Option.ofNonErrorObject
|
736
|
+
|> Option.renderParenthesized
|
803
737
|
|
804
738
|
type NucleotideCount() =
|
805
739
|
inherit GeneratorExercise()
|
806
740
|
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
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.
|
836
|
-
|>
|
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:
|
852
|
-
|
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:
|
857
|
-
let
|
858
|
-
let palindromeValue = jObject.Value<int>("value")
|
769
|
+
let toPalindromeProducts (value: JToken) =
|
770
|
+
let palindromeValue = value.Value<int>("value")
|
859
771
|
let factors =
|
860
|
-
|
861
|
-
|>
|
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.
|
870
|
-
|> Option.map toPalindromeProducts
|
871
|
-
|>
|
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
|
-
|
|
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",
|
898
|
-
match
|
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 =
|
814
|
+
let toClassification value = Obj.renderEnum "Classification" value
|
909
815
|
|
910
816
|
override __.RenderExpected (_, _, value) =
|
911
|
-
value
|
912
|
-
|> Option.
|
913
|
-
|> Option.map toClassification
|
914
|
-
|>
|
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.
|
923
|
-
|>
|
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
|
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:
|
853
|
+
member this.RenderNode (tree: JToken) : string =
|
950
854
|
match isNull tree with
|
951
855
|
| true -> ""
|
952
856
|
| false ->
|
953
|
-
let node =
|
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
|
-
|
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
|
-
|
1013
|
-
|
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
|
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
|
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" ->
|
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
|
-
|
|
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
|
-
|
|
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"]
|
978
|
+
canonicalDataCase.Input.["cells"]
|
1092
979
|
|> Seq.map (fun (cellValue: JToken) ->
|
1093
|
-
let
|
1094
|
-
|
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
|
-
|
984
|
+
cellValue.["compute_function"].ToObject<string>().Replace ("inputs", "values.")
|
1099
985
|
let inputParams =
|
1100
|
-
(
|
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 =
|
1105
|
-
sprintf "let %s = reactor.createInputCell %s" cellName (
|
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:
|
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
|
-
|
1136
|
-
|
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
|
-
|
1024
|
+
else
|
1025
|
+
Seq.empty
|
1140
1026
|
|
1141
|
-
let renderSetValueOperation (op:
|
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:
|
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:
|
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:
|
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"]
|
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 (
|
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" (
|
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:
|
1305
|
-
(input.Value<int>("row"), input.Value<int>("column"))
|
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.
|
1326
|
-
|>
|
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" ->
|
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
|
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
|
-
|
|
1374
|
-
|
|
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
|
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 (
|
1437
|
-
|
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:
|
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
|
1474
|
-
let
|
1475
|
-
let
|
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
|
1326
|
+
value
|
1327
|
+
|> Option.ofNonNull
|
1328
|
+
|> Option.renderParenthesized
|
1484
1329
|
|
1485
1330
|
type VariableLengthQuantity() =
|
1486
1331
|
inherit GeneratorExercise()
|
1487
1332
|
|
1488
|
-
let formatUnsignedByteList (value:
|
1489
|
-
value
|
1490
|
-
|>
|
1491
|
-
|> formatList
|
1333
|
+
let formatUnsignedByteList (value: JToken) =
|
1334
|
+
value.ToObject<byte list>()
|
1335
|
+
|> List.mapRender (sprintf "0x%xuy")
|
1492
1336
|
|
1493
|
-
let formatUnsignedIntList (value:
|
1494
|
-
value
|
1495
|
-
|>
|
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
|
1501
|
-
| "decode" -> value
|
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
|
1507
|
-
| "decode" ->
|
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
|
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
|
-
|
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 ->
|
1375
|
+
| false -> renderExpectedCoordinates value |> Some |> Option.renderString
|
1541
1376
|
|
1542
1377
|
override __.RenderExpected (_, _, value) =
|
1543
|
-
|
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
|
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" ->
|
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
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
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:
|
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:
|
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:
|
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:
|
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:
|
1475
|
+
let renderSut (operations: JToken) =
|
1650
1476
|
operations
|
1651
1477
|
|> renderOperations
|
1652
1478
|
|> sprintf "let sut = zipper %s"
|
1653
1479
|
|
1654
|
-
let renderExpected (expected:
|
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
|
1487
|
+
renderExpectedZipperWithIdentifier "expected" jObject expected.["operations"]
|
1662
1488
|
| _ ->
|
1663
1489
|
"let expected = None"
|
1664
1490
|
| "tree" ->
|
1665
|
-
expected.["value"]
|
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"]
|
1677
|
-
let sut = canonicalDataCase.Input.["operations"]
|
1678
|
-
let expected = canonicalDataCase.Expected
|
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 =
|