trackler 2.0.8.17 → 2.0.8.18
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/common/exercises/forth/canonical-data.json +307 -321
- data/common/exercises/largest-series-product/canonical-data.json +139 -122
- data/common/exercises/list-ops/canonical-data.json +162 -141
- data/common/exercises/markdown/canonical-data.json +15 -14
- data/common/exercises/pov/canonical-data.json +264 -116
- data/common/exercises/prime-factors/canonical-data.json +51 -40
- data/common/exercises/rail-fence-cipher/canonical-data.json +56 -44
- data/common/exercises/react/canonical-data.json +18 -4
- data/common/exercises/rectangles/canonical-data.json +16 -1
- data/common/exercises/rotational-cipher/canonical-data.json +81 -67
- data/common/exercises/run-length-encoding/canonical-data.json +89 -71
- data/common/exercises/space-age/canonical-data.json +61 -45
- data/common/exercises/sublist/canonical-data.json +136 -99
- data/common/exercises/transpose/canonical-data.json +207 -194
- data/common/exercises/variable-length-quantity/canonical-data.json +171 -141
- data/lib/trackler/version.rb +1 -1
- data/tracks/csharp/exercises/diamond/HINTS.md +9 -0
- data/tracks/go/README.md +3 -0
- data/tracks/go/exercises/queen-attack/queen_attack_test.go +1 -1
- data/tracks/haskell/exercises/hamming/src/Hamming.hs +2 -1
- data/tracks/java/exercises/flatten-array/src/test/java/FlattenerTest.java +5 -0
- data/tracks/ocaml/exercises/anagram/test.ml +2 -2
- data/tracks/ocaml/tools/test-generator/src/controller.ml +7 -2
- data/tracks/ocaml/tools/test-generator/src/parser.ml +31 -18
- data/tracks/ocaml/tools/test-generator/src/template.ml +10 -8
- data/tracks/ocaml/tools/test-generator/src/utils.ml +11 -0
- data/tracks/ocaml/tools/test-generator/templates/phone-number/template.ml +4 -5
- data/tracks/ocaml/tools/test-generator/test/beer-song.json +77 -0
- data/tracks/ocaml/tools/test-generator/test/difference_of_squares.json +76 -62
- data/tracks/ocaml/tools/test-generator/test/parser_test.ml +11 -9
- data/tracks/ocaml/tools/test-generator/test/template_test.ml +2 -2
- metadata +4 -2
@@ -1,147 +1,177 @@
|
|
1
1
|
{
|
2
|
-
"
|
2
|
+
"exercise": "variable-length-quantity",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"comments": [
|
3
5
|
"JSON doesn't allow hexadecimal literals.",
|
4
6
|
"All numbers are given as decimal literals instead.",
|
5
7
|
"It is highly recommended that your track's test generator display all numbers as hexadecimal literals."
|
6
8
|
],
|
7
|
-
"
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
9
|
+
"cases": [
|
10
|
+
{
|
11
|
+
"description": "Encode a series of integers, producing a series of bytes.",
|
12
|
+
"cases": [
|
13
|
+
{
|
14
|
+
"description": "zero",
|
15
|
+
"property": "encode",
|
16
|
+
"input": [0],
|
17
|
+
"expected": [0]
|
18
|
+
},
|
19
|
+
{
|
20
|
+
"description": "arbitrary single byte",
|
21
|
+
"property": "encode",
|
22
|
+
"input": [64],
|
23
|
+
"expected": [64]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"description": "largest single byte",
|
27
|
+
"property": "encode",
|
28
|
+
"input": [127],
|
29
|
+
"expected": [127]
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"description": "smallest double byte",
|
33
|
+
"property": "encode",
|
34
|
+
"input": [128],
|
35
|
+
"expected": [129,0]
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"description": "arbitrary double byte",
|
39
|
+
"property": "encode",
|
40
|
+
"input": [8192],
|
41
|
+
"expected": [192, 0]
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"description": "largest double byte",
|
45
|
+
"property": "encode",
|
46
|
+
"input": [16383],
|
47
|
+
"expected": [255, 127]
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"description": "smallest triple byte",
|
51
|
+
"property": "encode",
|
52
|
+
"input": [16384],
|
53
|
+
"expected": [129, 128, 0]
|
54
|
+
},
|
55
|
+
{
|
56
|
+
"description": "arbitrary triple byte",
|
57
|
+
"property": "encode",
|
58
|
+
"input": [1048576],
|
59
|
+
"expected": [192, 128, 0]
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"description": "largest triple byte",
|
63
|
+
"property": "encode",
|
64
|
+
"input": [2097151],
|
65
|
+
"expected": [255, 255, 127]
|
66
|
+
},
|
67
|
+
{
|
68
|
+
"description": "smallest quadruple byte",
|
69
|
+
"property": "encode",
|
70
|
+
"input": [2097152],
|
71
|
+
"expected": [129, 128, 128, 0]
|
72
|
+
},
|
73
|
+
{
|
74
|
+
"description": "arbitrary quadruple byte",
|
75
|
+
"property": "encode",
|
76
|
+
"input": [134217728],
|
77
|
+
"expected": [192, 128, 128, 0]
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"description": "largest quadruple byte",
|
81
|
+
"property": "encode",
|
82
|
+
"input": [268435455],
|
83
|
+
"expected": [255, 255, 255, 127]
|
84
|
+
},
|
85
|
+
{
|
86
|
+
"description": "smallest quintuple byte",
|
87
|
+
"property": "encode",
|
88
|
+
"input": [268435456],
|
89
|
+
"expected": [129, 128, 128, 128, 0]
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"description": "arbitrary quintuple byte",
|
93
|
+
"property": "encode",
|
94
|
+
"input": [4278190080],
|
95
|
+
"expected": [143, 248, 128, 128, 0]
|
96
|
+
},
|
97
|
+
{
|
98
|
+
"description": "maximum 32-bit integer input",
|
99
|
+
"property": "encode",
|
100
|
+
"input": [4294967295],
|
101
|
+
"expected": [143, 255, 255, 255, 127]
|
102
|
+
},
|
103
|
+
{
|
104
|
+
"description": "two single-byte values",
|
105
|
+
"property": "encode",
|
106
|
+
"input": [64, 127],
|
107
|
+
"expected": [64, 127]
|
108
|
+
},
|
109
|
+
{
|
110
|
+
"description": "two multi-byte values",
|
111
|
+
"property": "encode",
|
112
|
+
"input": [16384, 1193046],
|
113
|
+
"expected": [129, 128, 0, 200, 232, 86]
|
114
|
+
},
|
115
|
+
{
|
116
|
+
"description": "many multi-byte values",
|
117
|
+
"property": "encode",
|
118
|
+
"input": [8192, 1193046, 268435455, 0, 16383, 16384],
|
119
|
+
"expected": [192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0]
|
120
|
+
}
|
121
|
+
]
|
122
|
+
},
|
123
|
+
{
|
124
|
+
"description": "Decode a series of bytes, producing a series of integers.",
|
125
|
+
"cases": [
|
126
|
+
{
|
127
|
+
"description": "one byte",
|
128
|
+
"property": "decode",
|
129
|
+
"input": [127],
|
130
|
+
"expected": [127]
|
131
|
+
},
|
132
|
+
{
|
133
|
+
"description": "two bytes",
|
134
|
+
"property": "decode",
|
135
|
+
"input": [192, 0],
|
136
|
+
"expected": [8192]
|
137
|
+
},
|
138
|
+
{
|
139
|
+
"description": "three bytes",
|
140
|
+
"property": "decode",
|
141
|
+
"input": [255, 255, 127],
|
142
|
+
"expected": [2097151]
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"description": "four bytes",
|
146
|
+
"property": "decode",
|
147
|
+
"input": [129, 128, 128, 0],
|
148
|
+
"expected": [2097152]
|
149
|
+
},
|
150
|
+
{
|
151
|
+
"description": "maximum 32-bit integer",
|
152
|
+
"property": "decode",
|
153
|
+
"input": [143, 255, 255, 255, 127],
|
154
|
+
"expected": [4294967295]
|
155
|
+
},
|
156
|
+
{
|
157
|
+
"description": "incomplete sequence causes error",
|
158
|
+
"property": "decode",
|
159
|
+
"input": [255],
|
160
|
+
"expected": null
|
161
|
+
},
|
162
|
+
{
|
163
|
+
"description": "incomplete sequence causes error, even if value is zero",
|
164
|
+
"property": "decode",
|
165
|
+
"input": [128],
|
166
|
+
"expected": null
|
167
|
+
},
|
168
|
+
{
|
169
|
+
"description": "multiple values",
|
170
|
+
"property": "decode",
|
171
|
+
"input": [192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0],
|
172
|
+
"expected": [8192, 1193046, 268435455, 0, 16383, 16384]
|
173
|
+
}
|
174
|
+
]
|
175
|
+
}
|
176
|
+
]
|
147
177
|
}
|
data/lib/trackler/version.rb
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
## Hints
|
2
|
+
The tests in this exercise are different from your usual tests. Normally, a test checks if for a given input, the output matches the expected value. This is called *value-based testing*. However, this exercise uses *property-based testing*, where the tests check if for a range of inputs, the output has a specific property. The two key differences that differentiate property-based testing from value-based testing are:
|
3
|
+
|
4
|
+
1. A property-based test works not with a single input value, but with many.
|
5
|
+
1. A property-based test verifies properties, not concrete values.
|
6
|
+
|
7
|
+
For this exercise, the tests all verify a property of the diamond shape your code should be producing. Furthermore, all tests check if the property they test holds for all valid input letters ('A' to 'Z').
|
8
|
+
|
9
|
+
For more information on property-based testing, see [this article](http://www.erikschierboom.com/2016/02/22/property-based-testing/).
|
data/tracks/go/README.md
CHANGED
@@ -26,6 +26,9 @@ Test your clone by cding to the xgo directory and typing
|
|
26
26
|
Note that unlike most other Go code, it is not necessary to clone this to your GOPATH.
|
27
27
|
This is because this repo only imports from the standard library and isn't expected to be imported by other packages.
|
28
28
|
|
29
|
+
There is a [misspelling tool](https://github.com/client9/misspell). You can install and occasionally run it to
|
30
|
+
find low hanging typo problems. [#570](https://github.com/exercism/xgo/pull/570) It's not added into CI since it could give false positives.
|
31
|
+
|
29
32
|
## Contributing Guide
|
30
33
|
|
31
34
|
Please be familiar with the [contributing guide](https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md)
|
@@ -33,7 +33,7 @@ var tests = []struct {
|
|
33
33
|
|
34
34
|
func TestTestVersion(t *testing.T) {
|
35
35
|
if testVersion != targetTestVersion {
|
36
|
-
t.
|
36
|
+
t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
|
37
37
|
}
|
38
38
|
}
|
39
39
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import org.junit.Before;
|
2
2
|
import org.junit.Test;
|
3
|
+
import org.junit.Ignore;
|
3
4
|
|
4
5
|
import static java.util.Arrays.asList;
|
5
6
|
import static java.util.Collections.emptyList;
|
@@ -32,6 +33,7 @@ public final class FlattenerTest {
|
|
32
33
|
8)));
|
33
34
|
}
|
34
35
|
|
36
|
+
@Ignore
|
35
37
|
@Test
|
36
38
|
public void testFiveLevelsOfNestingWithNoNulls() {
|
37
39
|
assertEquals(
|
@@ -54,6 +56,7 @@ public final class FlattenerTest {
|
|
54
56
|
"-2")));
|
55
57
|
}
|
56
58
|
|
59
|
+
@Ignore
|
57
60
|
@Test
|
58
61
|
public void testSixLevelsOfNestingWithNoNulls() {
|
59
62
|
assertEquals(
|
@@ -76,6 +79,7 @@ public final class FlattenerTest {
|
|
76
79
|
"8")));
|
77
80
|
}
|
78
81
|
|
82
|
+
@Ignore
|
79
83
|
@Test
|
80
84
|
public void testSixLevelsOfNestingWithNulls() {
|
81
85
|
assertEquals(
|
@@ -99,6 +103,7 @@ public final class FlattenerTest {
|
|
99
103
|
"negative two")));
|
100
104
|
}
|
101
105
|
|
106
|
+
@Ignore
|
102
107
|
@Test
|
103
108
|
public void testNestedListsFullOfNullsOnly() {
|
104
109
|
assertEquals(
|
@@ -13,13 +13,13 @@ let tests = [
|
|
13
13
|
ae ["tan"] (anagrams "ant" ["tan"; "stand"; "at"]);
|
14
14
|
"does not detect false positives" >::
|
15
15
|
ae [] (anagrams "galea" ["eagle"]);
|
16
|
-
"detects
|
16
|
+
"detects two anagrams" >::
|
17
17
|
ae ["stream"; "maters"] (anagrams "master" ["stream"; "pigeon"; "maters"]);
|
18
18
|
"does not detect anagram subsets" >::
|
19
19
|
ae [] (anagrams "good" ["dog"; "goody"]);
|
20
20
|
"detects anagram" >::
|
21
21
|
ae ["inlets"] (anagrams "listen" ["enlists"; "google"; "inlets"; "banana"]);
|
22
|
-
"detects
|
22
|
+
"detects three anagrams" >::
|
23
23
|
ae ["gallery"; "regally"; "largely"] (anagrams "allergy" ["gallery"; "ballerina"; "regally"; "clergy"; "largely"; "leading"]);
|
24
24
|
"does not detect identical words" >::
|
25
25
|
ae ["cron"] (anagrams "corn" ["corn"; "dark"; "Corn"; "rank"; "CORN"; "cron"; "park"]);
|
@@ -22,6 +22,12 @@ let find_canonical_data_files = find_nested_files "canonical-data.json"
|
|
22
22
|
let combine_files (template_files: (string * content) list) (canonical_data_files: (string * content) list): (string * content * content) list =
|
23
23
|
List.filter_map template_files ~f:(fun (n,t) -> (List.Assoc.find canonical_data_files ~equal:String.equal n |> Option.map ~f:(fun c -> (n,t,c))))
|
24
24
|
|
25
|
+
(* pangram in the canonical data is a suite but it does not really need to be as there's only one group. Convert a Suite to
|
26
|
+
a Single test in this case, to simplify the template. *)
|
27
|
+
let simplify_single_test_suite tests = match tests with
|
28
|
+
| Suite [{name = name; cases = cases}] -> Single cases
|
29
|
+
| x -> x
|
30
|
+
|
25
31
|
let generate_code ~(slug: string) ~(template_file: content) ~(canonical_data_file: content): (content, content) Result.t =
|
26
32
|
let template = find_template template_file in
|
27
33
|
let edit_expected = edit_expected ~stringify:json_to_string ~slug in
|
@@ -30,7 +36,7 @@ let generate_code ~(slug: string) ~(template_file: content) ~(canonical_data_fil
|
|
30
36
|
let open Result.Monad_infix in
|
31
37
|
Result.of_option template ("cannot recognize file for " ^ slug ^ " as a template") >>= fun template ->
|
32
38
|
parse_json_text canonical_data_file (expected_key_name slug) (cases_name slug)
|
33
|
-
|> Result.map_error ~f:show_error >>= (function
|
39
|
+
|> Result.map_error ~f:show_error >>| simplify_single_test_suite >>= (function
|
34
40
|
| Single cases ->
|
35
41
|
fill_in_template template.template slug cases
|
36
42
|
|> fill_tests template
|
@@ -38,7 +44,6 @@ let generate_code ~(slug: string) ~(template_file: content) ~(canonical_data_fil
|
|
38
44
|
| Suite tests ->
|
39
45
|
List.map tests ~f:(fun {name;cases} -> (name, fill_in_template template.template name cases))
|
40
46
|
|> fill_suite template
|
41
|
-
|> Result.return
|
42
47
|
)
|
43
48
|
|
44
49
|
let output_tests (files: (string * content * content) list) (output_folder: string) ~(generated_folder: string): unit =
|
@@ -24,7 +24,7 @@ let parse_case (expected_key: string) (s: json): (case, error) Result.t = match
|
|
24
24
|
|
25
25
|
let parse_cases (text: string) (cases_key: string): (json, error) Result.t =
|
26
26
|
match from_string text |> member cases_key with
|
27
|
-
| `Null -> Error (TestMustHaveKeyCalledCases
|
27
|
+
| `Null -> Error (TestMustHaveKeyCalledCases cases_key)
|
28
28
|
| json -> Ok json
|
29
29
|
|
30
30
|
let parse_single (text: string) (expected_key: string) (cases_key: string): (tests, error) Result.t =
|
@@ -34,15 +34,34 @@ let parse_single (text: string) (expected_key: string) (cases_key: string): (tes
|
|
34
34
|
(sequence >> (List.map ~f:(parse_case expected_key))) >>= fun ts ->
|
35
35
|
Result.return (Single ts)
|
36
36
|
|
37
|
-
let
|
38
|
-
let
|
39
|
-
|
40
|
-
let
|
41
|
-
|
37
|
+
let rec to_cases case: (case list, error) Result.t =
|
38
|
+
let open Result.Monad_infix in
|
39
|
+
find_note case "description" NoDescription >>= to_string_note BadDescription >>= fun desc ->
|
40
|
+
let cases = List.Assoc.find case "cases" in
|
41
|
+
match cases with
|
42
|
+
| Some cases -> to_list_note UnrecognizedJson cases >>= fun cases ->
|
43
|
+
List.map cases ~f:(to_assoc_note UnrecognizedJson) |> sequence >>= fun x ->
|
44
|
+
List.map x ~f:to_cases |> sequence |> Result.map ~f:List.concat
|
45
|
+
| None ->
|
46
|
+
find_note case "expected" (NoExpected "expected") >>= fun expected ->
|
47
|
+
Result.return [{description = desc; parameters = case; expected = expected}]
|
48
|
+
|
49
|
+
let convert_cases_description_to_name desc =
|
50
|
+
String.lowercase desc |> String.substr_replace_all ~pattern:" " ~with_:"_"
|
42
51
|
|
43
|
-
let
|
44
|
-
|
45
|
-
|
52
|
+
let suite_case json: (test, error) Result.t =
|
53
|
+
let open Result.Monad_infix in
|
54
|
+
to_assoc_note UnrecognizedJson json >>= fun case ->
|
55
|
+
find_note case "description" NoDescription >>= to_string_note BadDescription >>= fun desc ->
|
56
|
+
find_note case "cases" ExpectingListOfCases >>= to_list_note ExpectingListOfCases >>= fun case_assocs ->
|
57
|
+
List.map ~f:(to_assoc_note ExpectingMapForCase) case_assocs |> sequence >>= fun cases ->
|
58
|
+
List.map cases ~f:to_cases |> sequence >>= fun cases ->
|
59
|
+
Result.return {name = convert_cases_description_to_name desc; cases = List.concat cases}
|
60
|
+
|
61
|
+
let suite_cases (json: json) (cases_key: string): (test list, error) Result.t =
|
62
|
+
let open Result.Monad_infix in
|
63
|
+
(member cases_key json |> to_list_note ExpectingListOfCases) >>= fun assoc_cases ->
|
64
|
+
List.map ~f:suite_case assoc_cases |> sequence
|
46
65
|
|
47
66
|
let parse_cases_from_suite name suite expected_key cases_key =
|
48
67
|
let open Result.Monad_infix in
|
@@ -53,15 +72,9 @@ let parse_cases_from_suite name suite expected_key cases_key =
|
|
53
72
|
let parse_json_text (text: string) (expected_key: string) (cases_key: string): (tests, error) Result.t =
|
54
73
|
let open Result.Monad_infix in
|
55
74
|
let json = from_string text in
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
let tests = List.filter tests ~f:(fun (n, _) -> n <> "#") in
|
60
|
-
let tests = List.map tests ~f:(fun (name, suite) -> merge_result (name, parse_cases_from_suite name suite expected_key cases_key)) in
|
61
|
-
sequence tests >>= fun tests ->
|
62
|
-
Ok (Suite tests)
|
63
|
-
else
|
64
|
-
parse_single text expected_key cases_key
|
75
|
+
match suite_cases json cases_key with
|
76
|
+
| Ok suite_cases -> Ok (Suite suite_cases)
|
77
|
+
| Error _ -> parse_single text expected_key cases_key
|
65
78
|
|
66
79
|
let show_error = function
|
67
80
|
| TestMustHaveKeyCalledCases name -> "Test named '" ^ name ^ "' is expected to have an object with a key: 'cases'"
|
@@ -40,21 +40,23 @@ let fill_tests (template: t) (substs: subst list): string =
|
|
40
40
|
let join = String.concat_array ~sep:"\n" in
|
41
41
|
String.concat [join before; join subst; join after] ~sep:"\n"
|
42
42
|
|
43
|
-
let fill_single_suite (template: t) (suite_substs: string * subst list): string =
|
43
|
+
let fill_single_suite (template: t) (suite_substs: string * subst list): (string, string) Result.t =
|
44
|
+
let open Result.Monad_infix in
|
44
45
|
let (suite_name, substs) = suite_substs in
|
45
|
-
|
46
|
-
|
46
|
+
Result.of_option template.suite_name_line ~error:"no suite name" >>= fun suite_name_line ->
|
47
|
+
Result.of_option template.suite_end ~error:"no suite end" >>= fun suite_end_line ->
|
47
48
|
let lines = String.split_lines template.file_text |> Fn.flip List.drop suite_name_line |> List.to_array in
|
48
49
|
Array.replace lines 0 ~f:(String.substr_replace_all ~pattern:"(* SUITE *)$(suite_name)_tests" ~with_:(suite_name ^ "_tests"));
|
49
50
|
let before = Array.slice lines 0 (template.start - suite_name_line) in
|
50
51
|
let subst = Array.of_list (List.map ~f:subst_to_string substs) in
|
51
52
|
let after = Array.slice lines (template.finish - suite_name_line + 1) (suite_end_line - suite_name_line) in
|
52
53
|
let join = String.concat_array ~sep:"\n" in
|
53
|
-
String.concat [join before; join subst; join after] ~sep:"\n"
|
54
|
+
Result.return @@ (String.concat [join before; join subst; join after] ~sep:"\n") ^ "\n"
|
54
55
|
|
55
|
-
let fill_suite (template: t) (suite_substs: (string * subst list) list): string =
|
56
|
-
let
|
57
|
-
|
56
|
+
let fill_suite (template: t) (suite_substs: (string * subst list) list): (string, string) Result.t =
|
57
|
+
let open Result.Monad_infix in
|
58
|
+
List.map suite_substs ~f:(fun x -> (fill_single_suite template x)) |> sequence >>= fun fills ->
|
59
|
+
Result.of_option template.suite_name_line "no suite name line" >>= fun suite_name_line ->
|
58
60
|
let lines = String.split_lines template.file_text |> List.to_array in
|
59
61
|
let before = Array.slice lines 0 suite_name_line in
|
60
62
|
let subst = Array.of_list fills in
|
@@ -62,4 +64,4 @@ let fill_suite (template: t) (suite_substs: (string * subst list) list): string
|
|
62
64
|
let join = String.concat_array ~sep:"\n" in
|
63
65
|
let generated = String.concat [join before; join subst; join after] ~sep:"\n" in
|
64
66
|
let all_suite_names = String.concat ~sep:"; " @@ List.map ~f:(fun (s,_) -> s ^ "_tests") suite_substs in
|
65
|
-
String.substr_replace_all generated ~pattern:"(* suite-all-names *)" ~with_:all_suite_names
|
67
|
+
Result.return @@ String.substr_replace_all generated ~pattern:"(* suite-all-names *)" ~with_:all_suite_names
|
@@ -27,15 +27,26 @@ let to_list_note error json =
|
|
27
27
|
let to_assoc_note error json =
|
28
28
|
try Ok (to_assoc json) with Type_error _ -> Error error
|
29
29
|
|
30
|
+
let to_assoc_option json =
|
31
|
+
try Some (to_assoc json) with Type_error _ -> None
|
32
|
+
|
30
33
|
let to_string_note error json =
|
31
34
|
try Ok (to_string json) with Type_error _ -> Error error
|
32
35
|
|
36
|
+
let to_string_option json =
|
37
|
+
try Some (to_string json) with _ -> None
|
38
|
+
|
33
39
|
let safe_to_int_option json =
|
34
40
|
try Some (to_int json) with Type_error _ -> None
|
35
41
|
|
36
42
|
let member_note error m json =
|
37
43
|
try Ok (member m json) with Type_error _ -> Error error
|
38
44
|
|
45
|
+
let find_note (xs: ('a, 'b) List.Assoc.t) (key: 'a) (error: 'e): ('b, 'e) Result.t =
|
46
|
+
match List.Assoc.find xs key with
|
47
|
+
| Some v -> Ok v
|
48
|
+
| None -> Error error
|
49
|
+
|
39
50
|
let (>>) f g = Fn.compose f g
|
40
51
|
|
41
52
|
let find_arrayi ?start:(start = 0) xs ~f =
|
@@ -9,13 +9,12 @@ let option_to_string f = function
|
|
9
9
|
let ae exp got _test_ctxt =
|
10
10
|
assert_equal ~printer:(option_to_string String.to_string) exp got
|
11
11
|
|
12
|
-
let
|
12
|
+
let tests = [
|
13
13
|
(* TEST
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
"$description" >::
|
15
|
+
ae $expected (number $phrase);
|
16
|
+
END TEST *)
|
17
17
|
]
|
18
|
-
(* END SUITE *)
|
19
18
|
|
20
19
|
let () =
|
21
20
|
run_test_tt_main ("phone-number tests" >::: number_tests)
|