trackler 2.2.1.19 → 2.2.1.20
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/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
|
]
|