trackler 2.2.1.19 → 2.2.1.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/bash/config.json +11 -0
- data/tracks/bash/docs/ABOUT.md +5 -0
- data/tracks/bash/exercises/word-count/README.md +24 -0
- data/tracks/bash/exercises/word-count/example.awk +12 -0
- data/tracks/bash/exercises/word-count/example.sh +21 -0
- data/tracks/bash/exercises/word-count/word_count_test.sh +84 -0
- data/tracks/coffeescript/config/maintainers.json +5 -11
- data/tracks/csharp/.travis.yml +3 -0
- data/tracks/delphi/config/maintainers.json +1 -1
- data/tracks/ecmascript/config.json +108 -108
- data/tracks/elixir/exercises/phone-number/phone_number_test.exs +21 -1
- data/tracks/factor/docs/SNIPPET.txt +5 -0
- data/tracks/idris/docs/TESTS.md +7 -0
- data/tracks/java/config.json +47 -47
- data/tracks/javascript/config.json +103 -103
- data/tracks/julia/config.json +121 -121
- data/tracks/julia/docs/RESOURCES.md +1 -1
- data/tracks/julia/docs/SNIPPET.txt +8 -0
- data/tracks/objective-c/config.json +2 -3
- data/tracks/objective-c/exercises/rna-transcription/RNATranscriptionExample.m +11 -32
- data/tracks/ocaml/.travis-ci.sh +1 -1
- data/tracks/ocaml/.travis.yml +1 -1
- data/tracks/ocaml/README.md +1 -1
- data/tracks/ocaml/exercises/change/test.ml +24 -21
- data/tracks/ocaml/tools/test-generator/src/codegen.ml +3 -7
- data/tracks/ocaml/tools/test-generator/src/controller.ml +4 -5
- data/tracks/ocaml/tools/test-generator/src/languages.ml +4 -3
- data/tracks/ocaml/tools/test-generator/src/model.ml +1 -2
- data/tracks/ocaml/tools/test-generator/src/ocaml_special_cases.ml +19 -18
- data/tracks/ocaml/tools/test-generator/src/parser.ml +12 -17
- data/tracks/ocaml/tools/test-generator/src/purescript_special_cases.ml +11 -3
- data/tracks/ocaml/tools/test-generator/test/codegen_test.ml +2 -3
- data/tracks/ocaml/tools/test-generator/test/ocaml_special_cases_test.ml +12 -4
- data/tracks/ocaml/tools/test-generator/test/parser_test.ml +10 -10
- data/tracks/purescript/exercises/bob/test/Main.purs +5 -5
- data/tracks/ruby/bin/generate +1 -1
- data/tracks/ruby/docs/24pullrequests.md +1 -1
- data/tracks/ruby/exercises/all-your-base/all_your_base_test.rb +24 -24
- data/tracks/ruby/exercises/alphametics/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/bowling/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/bowling/bowling_test.rb +10 -10
- data/tracks/ruby/exercises/change/.meta/.version +1 -1
- data/tracks/ruby/exercises/change/.meta/solutions/change.rb +1 -1
- data/tracks/ruby/exercises/change/change_test.rb +7 -2
- data/tracks/ruby/exercises/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb +1 -1
- data/tracks/ruby/exercises/connect/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/dominoes/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/hamming/.meta/generator/hamming_case.rb +5 -1
- data/tracks/ruby/exercises/hamming/hamming_test.rb +7 -7
- data/tracks/ruby/exercises/leap/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/pangram/.meta/.version +1 -1
- data/tracks/ruby/exercises/pangram/.meta/solutions/pangram.rb +1 -1
- data/tracks/ruby/exercises/pangram/pangram_test.rb +3 -3
- data/tracks/ruby/exercises/rna-transcription/rna_transcription_test.rb +4 -4
- data/tracks/ruby/exercises/roman-numerals/.meta/solutions/roman_numerals.rb +1 -1
- data/tracks/ruby/exercises/space-age/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/lib/generator/test_template.erb +1 -1
- data/tracks/ruby/lib/generator/underscore.rb +1 -1
- data/tracks/ruby/lib/helper.rb +4 -4
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha-beta/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/.version +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/generator/alpha_case.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/solutions/alpha.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/beta/.meta/.version +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/beta/.meta/generator/beta_case.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/lib/generator/test_template.erb +1 -1
- data/tracks/ruby/test/generator/files/track_files_test.rb +4 -4
- data/tracks/ruby/test/generator/implementation_test.rb +1 -1
- data/tracks/ruby/test/generator/template_values_test.rb +1 -1
- data/tracks/scala/exercises/rail-fence-cipher/src/main/scala/{RailFenceCipher.scala → .keep} +0 -0
- data/tracks/scala/exercises/rail-fence-cipher/src/test/scala/RailFenceCipherTest.scala +16 -23
- data/tracks/scala/exercises/say/src/test/scala/SayTest.scala +20 -33
- data/tracks/scala/testgen/src/main/scala/RailFenceCipherTestGenerator.scala +9 -53
- data/tracks/scala/testgen/src/main/scala/SayTestGenerator.scala +50 -0
- data/tracks/sml/bin/generate +1 -1
- data/tracks/sml/config.json +30 -0
- data/tracks/sml/exercises/all-your-base/README.md +61 -0
- data/tracks/sml/exercises/all-your-base/all-your-base.sml +2 -0
- data/tracks/sml/exercises/all-your-base/example.sml +36 -0
- data/tracks/sml/exercises/all-your-base/test.sml +75 -0
- data/tracks/sml/exercises/all-your-base/testlib.sml +159 -0
- data/tracks/sml/exercises/difference-of-squares/example.sml +3 -6
- data/tracks/sml/exercises/list-ops/README.md +40 -0
- data/tracks/sml/exercises/list-ops/example.sml +34 -0
- data/tracks/sml/exercises/list-ops/list-ops.sml +23 -0
- data/tracks/sml/exercises/list-ops/test.sml +85 -0
- data/tracks/sml/exercises/list-ops/testlib.sml +159 -0
- data/tracks/sml/exercises/prime-factors/README.md +66 -0
- data/tracks/sml/exercises/prime-factors/example.sml +15 -0
- data/tracks/sml/exercises/prime-factors/prime-factors.sml +2 -0
- data/tracks/sml/exercises/prime-factors/test.sml +35 -0
- data/tracks/sml/exercises/prime-factors/testlib.sml +159 -0
- metadata +34 -11
@@ -8,39 +8,18 @@
|
|
8
8
|
@"C" : @"G",
|
9
9
|
@"T" : @"A",
|
10
10
|
@"A" : @"U" };
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
|
12
|
+
NSMutableString *rnaStrand = [NSMutableString stringWithString:dnaStrand];
|
13
|
+
|
14
|
+
for (NSUInteger i = 0; i < [dnaStrand length]; i++) {
|
15
|
+
NSRange charRange = [dnaStrand rangeOfComposedCharacterSequenceAtIndex:i];
|
16
|
+
NSString *dnaNucleotide = [dnaStrand substringWithRange:charRange];
|
17
|
+
NSString *rnaNucleotide = dnaToRNADict[dnaNucleotide];
|
18
|
+
if (!rnaNucleotide) return nil;
|
19
|
+
[rnaStrand replaceCharactersInRange:charRange withString:rnaNucleotide];
|
18
20
|
}
|
19
|
-
|
20
|
-
|
21
|
-
NSMutableDictionary *dnaToRnaRanges = [NSMutableDictionary dictionary];
|
22
|
-
|
23
|
-
[[dnaToRNADict allKeys] enumerateObjectsUsingBlock:^(NSString *dnaKey, NSUInteger idx, BOOL * _Nonnull stop) {
|
24
|
-
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:dnaKey options:0 error:NULL];
|
25
|
-
NSMutableArray *ranges = [NSMutableArray array];
|
26
|
-
|
27
|
-
[regex enumerateMatchesInString:dnaStrand options:0 range:NSMakeRange(0, [dnaStrand length]) usingBlock:^(NSTextCheckingResult * _Nullable match, NSMatchingFlags flags, BOOL * _Nonnull stop) {
|
28
|
-
NSRange range = [match rangeAtIndex:0];
|
29
|
-
[ranges addObject:[NSValue valueWithRange:range]];
|
30
|
-
}];
|
31
|
-
|
32
|
-
dnaToRnaRanges[dnaKey] = [ranges copy];
|
33
|
-
}];
|
34
|
-
|
35
|
-
[dnaToRNADict enumerateKeysAndObjectsUsingBlock:^(NSString *dnaKey, NSString *rnaValue, BOOL * _Nonnull stop) {
|
36
|
-
NSArray *dnaRanges = dnaToRnaRanges[dnaKey];
|
37
|
-
|
38
|
-
[dnaRanges enumerateObjectsUsingBlock:^(NSValue *dnaRangeValue, NSUInteger idx, BOOL * _Nonnull stop) {
|
39
|
-
[rna replaceOccurrencesOfString:dnaKey withString:rnaValue options:NSLiteralSearch range:[dnaRangeValue rangeValue]];
|
40
|
-
}];
|
41
|
-
}];
|
42
|
-
|
43
|
-
return [rna copy];
|
21
|
+
|
22
|
+
return [rnaStrand copy];
|
44
23
|
}
|
45
24
|
|
46
25
|
@end
|
data/tracks/ocaml/.travis-ci.sh
CHANGED
data/tracks/ocaml/.travis.yml
CHANGED
data/tracks/ocaml/README.md
CHANGED
@@ -11,7 +11,7 @@ notes contain a few details specific to Ocaml.
|
|
11
11
|
|
12
12
|
## Prerequisites
|
13
13
|
|
14
|
-
The OCaml track assumes installation of OCaml version 4.
|
14
|
+
The OCaml track assumes installation of OCaml version 4.05.0, and installation of Core, OUnit, and React (for the Hangman exercise).
|
15
15
|
Assuming you have opam, these can be installed with
|
16
16
|
```bash
|
17
17
|
opam install core ounit react
|
@@ -1,4 +1,4 @@
|
|
1
|
-
(* Test/exercise version: "1.
|
1
|
+
(* Test/exercise version: "1.1.0" *)
|
2
2
|
|
3
3
|
open Core
|
4
4
|
open OUnit2
|
@@ -9,35 +9,38 @@ let ae exp got _test_ctxt = assert_equal ~printer exp got
|
|
9
9
|
|
10
10
|
let tests = [
|
11
11
|
"single coin change" >::
|
12
|
-
|
13
|
-
|
12
|
+
ae (Some [25])
|
13
|
+
(make_change ~target:25 ~coins:[1; 5; 10; 25; 100]);
|
14
14
|
"multiple coin change" >::
|
15
|
-
|
16
|
-
|
15
|
+
ae (Some [5; 10])
|
16
|
+
(make_change ~target:15 ~coins:[1; 5; 10; 25; 100]);
|
17
17
|
"change with Lilliputian Coins" >::
|
18
|
-
|
19
|
-
|
18
|
+
ae (Some [4; 4; 15])
|
19
|
+
(make_change ~target:23 ~coins:[1; 4; 15; 20; 50]);
|
20
20
|
"change with Lower Elbonia Coins" >::
|
21
|
-
|
22
|
-
|
21
|
+
ae (Some [21; 21; 21])
|
22
|
+
(make_change ~target:63 ~coins:[1; 5; 10; 21; 25]);
|
23
23
|
"large target values" >::
|
24
|
-
|
25
|
-
|
24
|
+
ae (Some [2; 2; 5; 20; 20; 50; 100; 100; 100; 100; 100; 100; 100; 100; 100])
|
25
|
+
(make_change ~target:999 ~coins:[1; 2; 5; 10; 20; 50; 100]);
|
26
26
|
"possible change without unit coins available" >::
|
27
|
-
|
28
|
-
|
27
|
+
ae (Some [2; 2; 2; 5; 10])
|
28
|
+
(make_change ~target:21 ~coins:[2; 5; 10; 20; 50]);
|
29
|
+
"another possible change without unit coins available" >::
|
30
|
+
ae (Some [4; 4; 4; 5; 5; 5])
|
31
|
+
(make_change ~target:27 ~coins:[4; 5]);
|
29
32
|
"no coins make 0 change" >::
|
30
|
-
|
31
|
-
|
33
|
+
ae (Some [])
|
34
|
+
(make_change ~target:0 ~coins:[1; 5; 10; 21; 25]);
|
32
35
|
"error testing for change smaller than the smallest of coins" >::
|
33
|
-
|
34
|
-
|
36
|
+
ae None
|
37
|
+
(make_change ~target:3 ~coins:[5; 10]);
|
35
38
|
"error if no combination can add up to target" >::
|
36
|
-
|
37
|
-
|
39
|
+
ae None
|
40
|
+
(make_change ~target:94 ~coins:[5; 10]);
|
38
41
|
"cannot find negative change values" >::
|
39
|
-
|
40
|
-
|
42
|
+
ae None
|
43
|
+
(make_change ~target:(-5) ~coins:[1; 2; 5]);
|
41
44
|
]
|
42
45
|
|
43
46
|
let () =
|
@@ -3,8 +3,6 @@ open Core
|
|
3
3
|
open Model
|
4
4
|
open Yojson.Basic
|
5
5
|
|
6
|
-
type edit_expected_function = value: json -> string
|
7
|
-
|
8
6
|
type edit_parameters_function = (string * json) list -> (string * string) list
|
9
7
|
|
10
8
|
type subst = Subst of string [@@deriving eq, show]
|
@@ -18,13 +16,11 @@ let replace_key (key: string) (value: string) (target: string): string =
|
|
18
16
|
let replace = String.substr_replace_all ~with_:value in
|
19
17
|
replace ~pattern:("$" ^ key) target |> replace ~pattern:("$(" ^ key ^ ")")
|
20
18
|
|
21
|
-
let rec replace_keys (
|
19
|
+
let rec replace_keys (ed: edit_parameters_function) (s: string) (suite_name: string) (c: case): subst =
|
22
20
|
let s = replace_key "description" c.description s in
|
23
|
-
let expected = f ~value:c.expected in
|
24
|
-
let s = replace_key "expected" expected s in
|
25
21
|
let s = replace_key "suite-name" suite_name s in
|
26
22
|
let parameter_strings = ed @@ List.map ~f:(fun (k,p) -> (k,p)) c.parameters in
|
27
23
|
List.fold parameter_strings ~init:(Subst s) ~f:(fun (Subst s) (k,v) -> Subst (replace_key k v s))
|
28
24
|
|
29
|
-
let fill_in_template (
|
30
|
-
List.map cases ~f:(replace_keys
|
25
|
+
let fill_in_template (ed: edit_parameters_function) (test_template: string) (suite_name: string) (cases: case list) =
|
26
|
+
List.map cases ~f:(replace_keys ed test_template suite_name)
|
@@ -39,13 +39,12 @@ let prepend_version (version_printer: string -> string) (v: string option) (str:
|
|
39
39
|
let generate_code ~(lc: language_config) ~(slug: string) ~(template_file: content) ~(canonical_data_file: content): (content, string) Result.t =
|
40
40
|
let open Result.Monad_infix in
|
41
41
|
Result.of_option ~error:("cannot recognize file for " ^ slug ^ " as a template") @@ find_template template_file lc.test_start_marker lc.test_end_marker >>= fun template ->
|
42
|
-
let
|
43
|
-
let
|
44
|
-
let fill_in_template = fill_in_template edit_expected edit_parameters in
|
42
|
+
let edit_parameters = lc.edit_parameters ~slug in
|
43
|
+
let fill_in_template = fill_in_template edit_parameters in
|
45
44
|
let file_text = template.file_text in
|
46
45
|
let file_lines = String.split_lines file_text |> List.to_array in
|
47
46
|
let prepend_version = prepend_version lc.version_printer in
|
48
|
-
parse_json_text canonical_data_file "
|
47
|
+
parse_json_text canonical_data_file "cases"
|
49
48
|
|> Result.map_error ~f:show_error >>| simplify_single_test_suite >>= fun cd -> (match cd.tests with
|
50
49
|
| Single cases ->
|
51
50
|
let template = to_single template.template in
|
@@ -89,7 +88,7 @@ let check_canonical_data canonical_data_folder =
|
|
89
88
|
let canonical_data_files = List.sort canonical_data_files ~cmp:(fun (s1, _) (s2, _) -> String.compare s1 s2) in
|
90
89
|
let total_count = List.length canonical_data_files in
|
91
90
|
List.iter canonical_data_files ~f:(fun (slug, text) ->
|
92
|
-
match parse_json_text text "
|
91
|
+
match parse_json_text text "cases" with
|
93
92
|
| Error e -> print_endline @@ slug ^ ": " ^ (show_error e)
|
94
93
|
| _ -> ok_count := !ok_count + 1
|
95
94
|
);
|
@@ -1,6 +1,7 @@
|
|
1
1
|
open Core
|
2
2
|
open Yojson.Basic
|
3
3
|
include Ocaml_special_cases
|
4
|
+
include Purescript_special_cases
|
4
5
|
|
5
6
|
type language_config = {
|
6
7
|
template_file_name: string;
|
@@ -8,7 +9,7 @@ type language_config = {
|
|
8
9
|
test_start_marker: string;
|
9
10
|
test_end_marker: string;
|
10
11
|
version_printer: string -> string;
|
11
|
-
|
12
|
+
edit_parameters: slug: string -> (string * json) list -> (string * string) list;
|
12
13
|
}
|
13
14
|
|
14
15
|
let default_language_config = function
|
@@ -18,7 +19,7 @@ let default_language_config = function
|
|
18
19
|
test_start_marker = "(* TEST";
|
19
20
|
test_end_marker = "END TEST";
|
20
21
|
version_printer = (fun v -> "(* Test/exercise version: \"" ^ v ^ "\" *)\n\n");
|
21
|
-
|
22
|
+
edit_parameters = ocaml_edit_parameters
|
22
23
|
}
|
23
24
|
| "purescript" -> {
|
24
25
|
template_file_name = "Main.purs";
|
@@ -26,7 +27,7 @@ let default_language_config = function
|
|
26
27
|
test_start_marker = "--TEST";
|
27
28
|
test_end_marker = "--END TEST";
|
28
29
|
version_printer = (fun v -> "-- Test/exercise version: \"" ^ v ^ "\"\n\n");
|
29
|
-
|
30
|
+
edit_parameters = purescript_edit_parameters
|
30
31
|
}
|
31
32
|
| x -> failwith @@ "unknown language " ^ x
|
32
33
|
|
@@ -62,21 +62,10 @@ let edit_bowling_expected (value: json) = match value with
|
|
62
62
|
if k = "error" then "(Error " ^ json_to_string v ^ ")" else failwith ("Can only handle error value but got " ^ k)
|
63
63
|
| _ -> failwith "Bad json value in bowling"
|
64
64
|
|
65
|
-
let ocaml_edit_expected ~(stringify: json -> string) ~(slug: string) ~(value: json) = match slug with
|
66
|
-
| "hamming" -> optional_int ~none:(-1) value
|
67
|
-
| "all-your-base" -> optional_int_list value
|
68
|
-
| "say" -> optional_int_or_string ~none:(-1) value
|
69
|
-
| "phone-number" -> option_of_null value
|
70
|
-
| "connect" -> edit_connect_expected value
|
71
|
-
| "change" -> edit_change_expected value
|
72
|
-
| "bowling" -> edit_bowling_expected value
|
73
|
-
| "binary-search" -> optional_int ~none:(-1) value
|
74
|
-
| "forth" -> option_of_null value
|
75
|
-
| _ -> stringify value
|
76
|
-
|
77
65
|
let edit_say (ps: (string * json) list) =
|
78
66
|
let edit = function
|
79
67
|
| ("input", v) -> ("input", let v = json_to_string v in if Int.of_string v >= 0 then "(" ^ v ^ "L)" else v ^ "L")
|
68
|
+
| ("expected", v) -> ("expected", optional_int_or_string ~none:(-1) v)
|
80
69
|
| (k, ps) -> (k, json_to_string ps) in
|
81
70
|
List.map ps ~f:edit
|
82
71
|
|
@@ -84,6 +73,7 @@ let edit_all_your_base (ps: (string * json) list): (string * string) list =
|
|
84
73
|
let edit = function
|
85
74
|
| ("output_base", v) -> let v = json_to_string v in ("output_base", if Int.of_string v >= 0 then v else "(" ^ v ^ ")")
|
86
75
|
| ("input_base", v) -> let v = json_to_string v in ("input_base", if Int.of_string v >= 0 then v else "(" ^ v ^ ")")
|
76
|
+
| ("expected", v) -> ("expected", optional_int_list v)
|
87
77
|
| (k, v) -> (k, json_to_string v) in
|
88
78
|
List.map ps ~f:edit
|
89
79
|
|
@@ -96,7 +86,6 @@ let edit_dominoes (ps: (string * json) list): (string * string) list =
|
|
96
86
|
| (k, v) -> (k, json_to_string v) in
|
97
87
|
List.map ps ~f:edit
|
98
88
|
|
99
|
-
|
100
89
|
let edit_space_age (ps: (string * json) list): (string * string) list =
|
101
90
|
let edit = function
|
102
91
|
| ("planet", v) -> ("planet", json_to_string v |> strip_quotes)
|
@@ -107,6 +96,7 @@ let edit_bowling (ps: (string * json) list): (string * string) list =
|
|
107
96
|
let edit = function
|
108
97
|
| ("property", v) -> ("property", json_to_string v |> strip_quotes)
|
109
98
|
| ("roll", `Int n) -> ("roll", let s = Int.to_string n in if n < 0 then ("(" ^ s ^ ")") else s)
|
99
|
+
| ("expected", v) -> ("expected", edit_bowling_expected v)
|
110
100
|
| (k, v) -> (k, json_to_string v) in
|
111
101
|
List.map ps ~f:edit
|
112
102
|
|
@@ -117,15 +107,26 @@ let edit_binary_search (ps: (string * json) list): (string * string) list =
|
|
117
107
|
"[|" ^ String.concat ~sep:"; " xs ^ "|]" in
|
118
108
|
let edit = function
|
119
109
|
| ("array", v) -> ("array", as_array_string v)
|
110
|
+
| ("expected", v) -> ("expected", optional_int ~none:(-1) v)
|
120
111
|
| (k, v) -> (k, json_to_string v) in
|
121
112
|
List.map ps ~f:edit
|
122
113
|
|
123
|
-
let
|
124
|
-
|
|
125
|
-
| ("
|
114
|
+
let rec edit_expected ~(f: json -> string) (parameters: (string * json) list) = match parameters with
|
115
|
+
| [] -> []
|
116
|
+
| ("expected", v) :: rest -> ("expected", f v) :: edit_expected f rest
|
117
|
+
| (k, v) :: rest -> (k, json_to_string v) :: edit_expected f rest
|
118
|
+
|
119
|
+
let ocaml_edit_parameters ~(slug: string) (parameters: (string * json) list) = match (slug, parameters) with
|
126
120
|
| ("all-your-base", ps) -> edit_all_your_base ps
|
121
|
+
| ("binary-search", ps) -> edit_binary_search ps
|
122
|
+
| ("bowling", ps) -> edit_bowling ps
|
123
|
+
| ("change", ps) -> edit_expected ~f:edit_change_expected ps
|
124
|
+
| ("connect", ps) -> edit_expected ~f:edit_connect_expected ps
|
127
125
|
| ("dominoes", ps) -> edit_dominoes ps
|
126
|
+
| ("forth", ps) -> edit_expected ~f:option_of_null ps
|
127
|
+
| ("hamming", ps) -> edit_expected ~f:(optional_int ~none:(-1)) ps
|
128
|
+
| ("hello-world", ps) -> default_value ~key:"name" ~value:"None" (optional_strings ~f:(fun _ -> true) parameters)
|
129
|
+
| ("phone-number", ps) -> edit_expected ~f:option_of_null ps
|
130
|
+
| ("say", ps) -> edit_say ps
|
128
131
|
| ("space-age", ps) -> edit_space_age ps
|
129
|
-
| ("bowling", ps) -> edit_bowling ps
|
130
|
-
| ("binary-search", ps) -> edit_binary_search ps
|
131
132
|
| (_, ps) -> map_elements json_to_string ps
|
@@ -6,20 +6,18 @@ open Model
|
|
6
6
|
|
7
7
|
type error =
|
8
8
|
TestMustHaveKeyCalledCases of string | ExpectingListOfCases | ExpectingMapForCase |
|
9
|
-
NoDescription | BadDescription |
|
9
|
+
NoDescription | BadDescription | UnrecognizedJson [@@deriving eq, show]
|
10
10
|
|
11
|
-
let parse_case_assoc (parameters: (string * json) list)
|
11
|
+
let parse_case_assoc (parameters: (string * json) list): (case, error) Result.t =
|
12
12
|
let find name e = List.Assoc.find parameters ~equal:String.equal name |> Result.of_option ~error:e in
|
13
13
|
let test_parameters = List.Assoc.remove parameters ~equal:String.equal "description" in
|
14
|
-
let test_parameters = List.Assoc.remove test_parameters ~equal:String.equal expected_key in
|
15
14
|
let open Result.Monad_infix in
|
16
15
|
find "description" NoDescription >>=
|
17
16
|
to_string_note BadDescription >>= fun description ->
|
18
|
-
|
19
|
-
Ok {description = description; parameters = test_parameters; expected = expected}
|
17
|
+
Ok {description = description; parameters = test_parameters}
|
20
18
|
|
21
|
-
let parse_case (
|
22
|
-
| `Assoc assoc -> parse_case_assoc assoc
|
19
|
+
let parse_case (s: json): (case, error) Result.t = match s with
|
20
|
+
| `Assoc assoc -> parse_case_assoc assoc
|
23
21
|
| _ -> Error ExpectingMapForCase
|
24
22
|
|
25
23
|
let parse_cases (text: string) (cases_key: string): (json, error) Result.t =
|
@@ -27,11 +25,11 @@ let parse_cases (text: string) (cases_key: string): (json, error) Result.t =
|
|
27
25
|
| `Null -> Error (TestMustHaveKeyCalledCases cases_key)
|
28
26
|
| json -> Ok json
|
29
27
|
|
30
|
-
let parse_single (text: string) (
|
28
|
+
let parse_single (text: string) (cases_key: string): (tests, error) Result.t =
|
31
29
|
let open Result.Monad_infix in
|
32
30
|
parse_cases text cases_key >>=
|
33
31
|
to_list_note ExpectingListOfCases >>=
|
34
|
-
(sequence >> (List.map ~f:
|
32
|
+
(sequence >> (List.map ~f:parse_case)) >>= fun ts ->
|
35
33
|
Result.return (Single ts)
|
36
34
|
|
37
35
|
let rec to_cases case: (case list, error) Result.t =
|
@@ -43,8 +41,7 @@ let rec to_cases case: (case list, error) Result.t =
|
|
43
41
|
List.map cases ~f:(to_assoc_note UnrecognizedJson) |> sequence >>= fun x ->
|
44
42
|
List.map x ~f:to_cases |> sequence |> Result.map ~f:List.concat
|
45
43
|
| None ->
|
46
|
-
|
47
|
-
Result.return [{description = desc; parameters = case; expected = expected}]
|
44
|
+
Result.return [{description = desc; parameters = case}]
|
48
45
|
|
49
46
|
let convert_cases_description_to_name desc =
|
50
47
|
String.lowercase desc |> String.substr_replace_all ~pattern:" " ~with_:"_"
|
@@ -63,19 +60,19 @@ let suite_cases (json: json) (cases_key: string): (test list, error) Result.t =
|
|
63
60
|
(member cases_key json |> to_list_note ExpectingListOfCases) >>= fun assoc_cases ->
|
64
61
|
List.map ~f:suite_case assoc_cases |> sequence
|
65
62
|
|
66
|
-
let parse_cases_from_suite name suite
|
63
|
+
let parse_cases_from_suite name suite cases_key =
|
67
64
|
let open Result.Monad_infix in
|
68
65
|
member_note (TestMustHaveKeyCalledCases name) cases_key suite >>=
|
69
66
|
to_list_note ExpectingListOfCases >>= fun tests ->
|
70
|
-
List.map tests ~f:
|
67
|
+
List.map tests ~f:parse_case |> sequence
|
71
68
|
|
72
|
-
let parse_json_text (text: string) (
|
69
|
+
let parse_json_text (text: string) (cases_key: string): (canonical_data, error) Result.t =
|
73
70
|
let open Result.Monad_infix in
|
74
71
|
let json = from_string text in
|
75
72
|
let version = member "version" json |> to_string_option in
|
76
73
|
match suite_cases json cases_key with
|
77
74
|
| Ok suite_cases -> Ok {version; tests=(Suite suite_cases)}
|
78
|
-
| Error _ -> parse_single text
|
75
|
+
| Error _ -> parse_single text cases_key >>= fun tests -> Ok {version; tests}
|
79
76
|
|
80
77
|
let show_error = function
|
81
78
|
| TestMustHaveKeyCalledCases name -> "Test named '" ^ name ^ "' is expected to have an object with a key: 'cases'"
|
@@ -83,6 +80,4 @@ let show_error = function
|
|
83
80
|
| ExpectingListOfCases -> "Expected a top level map with key cases, and a list of cases as its value."
|
84
81
|
| NoDescription -> "Case is missing a description."
|
85
82
|
| BadDescription -> "Description is not a string."
|
86
|
-
| NoExpected s -> "Case '" ^ s ^ "' is missing an expected key."
|
87
|
-
| BadExpected -> "Do not understand type of Expected key."
|
88
83
|
| UnrecognizedJson -> "Cannot understand this json."
|
@@ -3,11 +3,19 @@ open Core
|
|
3
3
|
open Model
|
4
4
|
open Yojson.Basic
|
5
5
|
|
6
|
+
let map_elements (to_str: json -> string) (parameters: (string * json) list): (string * string) list =
|
7
|
+
List.map parameters ~f:(fun (k,j) -> (k,to_str j))
|
8
|
+
|
6
9
|
let optional_int ~(none: int) = function
|
7
10
|
| `Int n when n = none -> "Nothing"
|
8
11
|
| `Int n -> "(Just " ^ Int.to_string n ^ ")"
|
9
12
|
| x -> json_to_string x
|
10
13
|
|
11
|
-
let edit_expected ~(
|
12
|
-
|
|
13
|
-
|
|
14
|
+
let rec edit_expected ~(f: json -> string) (parameters: (string * json) list) = match parameters with
|
15
|
+
| [] -> []
|
16
|
+
| ("expected", v) :: rest -> ("expected", f v) :: edit_expected f rest
|
17
|
+
| (k, v) :: rest -> (k, json_to_string v) :: edit_expected f rest
|
18
|
+
|
19
|
+
let purescript_edit_parameters ~(slug: string) (parameters: (string * json) list) = match (slug, parameters) with
|
20
|
+
| ("hamming", ps) -> edit_expected ~f:(optional_int ~none:(-1)) ps
|
21
|
+
| (_, ps) -> map_elements json_to_string ps
|
@@ -6,12 +6,11 @@ open Yojson.Basic
|
|
6
6
|
|
7
7
|
let leap_template = "\"$description\" >:: ae $expected (leap_year $input);"
|
8
8
|
|
9
|
-
let edit_expected ~value = json_to_string value
|
10
9
|
let edit_parameters (j: (string * json) list): (string * string) list =
|
11
10
|
List.map ~f:(fun (k,v) -> (k,to_string v)) j
|
12
11
|
let assert_fill_in_template exp cases = assert_equal exp
|
13
12
|
~printer:(fun xs -> "[" ^ (String.concat ~sep:";" xs) ^ "]")
|
14
|
-
(fill_in_template
|
13
|
+
(fill_in_template edit_parameters leap_template "suite-name" cases |> List.map ~f:subst_to_string)
|
15
14
|
let ae exp cases _test_ctxt = assert_fill_in_template exp cases
|
16
15
|
|
17
16
|
let codegen_tests = [
|
@@ -19,7 +18,7 @@ let codegen_tests = [
|
|
19
18
|
ae [] [];
|
20
19
|
|
21
20
|
"generates one function based on leap year for one case" >::(fun ctxt ->
|
22
|
-
let c = {description = "leap_year"; parameters = [("input", `Int 1996)
|
21
|
+
let c = {description = "leap_year"; parameters = [("input", `Int 1996); ("expected", `Bool true)];} in
|
23
22
|
assert_fill_in_template ["\"leap_year\" >:: ae true (leap_year 1996);"] [c]
|
24
23
|
);
|
25
24
|
]
|