trackler 2.0.3.2 → 2.0.3.3
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/c/config.json +10 -0
- data/tracks/c/exercises/robot-simulator/makefile +16 -0
- data/tracks/c/exercises/robot-simulator/src/example.c +74 -0
- data/tracks/c/exercises/robot-simulator/src/robot_simulator.h +41 -0
- data/tracks/c/exercises/robot-simulator/test/test_robot_simulator.c +165 -0
- data/tracks/c/exercises/robot-simulator/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/robot-simulator/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/robot-simulator/test/vendor/unity_internals.h +701 -0
- data/tracks/ecmascript/exercises/rna-transcription/example.js +9 -2
- data/tracks/ecmascript/exercises/rna-transcription/rna-transcription.spec.js +18 -0
- data/tracks/go/exercises/hello-world/example.go +4 -2
- data/tracks/go/exercises/hello-world/hello_test.go +4 -4
- data/tracks/go/exercises/hello-world/hello_world.go +6 -6
- data/tracks/groovy/config.json +5 -0
- data/tracks/groovy/exercises/phone-number/Example.groovy +20 -0
- data/tracks/groovy/exercises/phone-number/PhoneNumberSpec.groovy +75 -0
- data/tracks/haskell/exercises/difference-of-squares/test/Tests.hs +2 -0
- data/tracks/java/config.json +13 -1
- data/tracks/java/exercises/all-your-base/build.gradle +17 -0
- data/tracks/java/exercises/all-your-base/src/example/java/BaseConverter.java +80 -0
- data/tracks/java/exercises/all-your-base/src/main/java/BaseConverter.java +5 -0
- data/tracks/java/exercises/all-your-base/src/test/java/BaseConverterTest.java +256 -0
- data/tracks/java/exercises/binary-search/build.gradle +17 -0
- data/tracks/java/exercises/binary-search/src/example/java/BinarySearch.java +40 -0
- data/tracks/java/exercises/binary-search/src/main/java/.keep +0 -0
- data/tracks/java/exercises/binary-search/src/main/java/BinarySearch.java +4 -0
- data/tracks/java/exercises/binary-search/src/test/java/.keep +0 -0
- data/tracks/java/exercises/binary-search/src/test/java/BinarySearchTest.java +136 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/lua/config.json +16 -0
- data/tracks/lua/exercises/say/example.lua +92 -0
- data/tracks/lua/exercises/say/say_spec.lua +105 -0
- data/tracks/lua/exercises/secret-handshake/example.lua +17 -0
- data/tracks/lua/exercises/secret-handshake/secret-handshake_spec.lua +38 -0
- data/tracks/ocaml/config.json +10 -1
- data/tracks/ocaml/exercises/bracket-push/.merlin +3 -0
- data/tracks/ocaml/exercises/bracket-push/Makefile +11 -0
- data/tracks/ocaml/exercises/bracket-push/bracket_push.mli +3 -0
- data/tracks/ocaml/exercises/bracket-push/example.ml +40 -0
- data/tracks/ocaml/exercises/bracket-push/test.ml +38 -0
- data/tracks/ocaml/exercises/leap/test.ml +7 -7
- data/tracks/ocaml/tools/test-generator/Makefile +2 -2
- data/tracks/ocaml/tools/test-generator/interfaces/codegen.mli +2 -2
- data/tracks/ocaml/tools/test-generator/interfaces/{test_generator.mli → controller.mli} +0 -0
- data/tracks/ocaml/tools/test-generator/interfaces/parser.mli +7 -1
- data/tracks/ocaml/tools/test-generator/interfaces/special_cases.mli +2 -2
- data/tracks/ocaml/tools/test-generator/interfaces/utils.mli +4 -0
- data/tracks/ocaml/tools/test-generator/src/codegen.ml +9 -5
- data/tracks/ocaml/tools/test-generator/src/{test_generator.ml → controller.ml} +24 -15
- data/tracks/ocaml/tools/test-generator/src/model.ml +6 -0
- data/tracks/ocaml/tools/test-generator/src/parser.ml +34 -7
- data/tracks/ocaml/tools/test-generator/src/special_cases.ml +11 -4
- data/tracks/ocaml/tools/test-generator/src/template.ml +49 -6
- data/tracks/ocaml/tools/test-generator/src/test_gen.ml +1 -1
- data/tracks/ocaml/tools/test-generator/src/utils.ml +6 -0
- data/tracks/ocaml/tools/test-generator/templates/anagram/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/bob/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/bracket-push/template.ml +16 -0
- data/tracks/ocaml/tools/test-generator/templates/difference-of-squares/template.ml +19 -0
- data/tracks/ocaml/tools/test-generator/templates/hamming/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/hello-world/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/leap/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/raindrops/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/templates/say/template.ml +3 -3
- data/tracks/ocaml/tools/test-generator/templates/word-count/template.ml +2 -2
- data/tracks/ocaml/tools/test-generator/test/all_tests.ml +3 -1
- data/tracks/ocaml/tools/test-generator/test/codegen_test.ml +7 -7
- data/tracks/ocaml/tools/test-generator/test/difference_of_squares.json +67 -0
- data/tracks/ocaml/tools/test-generator/test/hello_world.json +23 -0
- data/tracks/ocaml/tools/test-generator/test/parser_test.ml +30 -12
- data/tracks/ocaml/tools/test-generator/test/sample-suite-template.txt +16 -0
- data/tracks/ocaml/tools/test-generator/test/sample_template.txt +2 -2
- data/tracks/ocaml/tools/test-generator/test/special_cases_test.ml +1 -1
- data/tracks/ocaml/tools/test-generator/test/template_test.ml +40 -6
- data/tracks/perl6/.travis.yml +3 -0
- data/tracks/perl6/docs/RESOURCES.md +1 -1
- data/tracks/perl6/exercises/accumulate/accumulate.t +3 -7
- data/tracks/perl6/exercises/anagram/anagram.t +3 -7
- data/tracks/perl6/exercises/binary/binary.t +3 -7
- data/tracks/perl6/exercises/bob/bob.t +4 -8
- data/tracks/perl6/exercises/grains/grains.t +3 -7
- data/tracks/perl6/exercises/leap/leap.t +3 -7
- data/tracks/perl6/exercises/rna-transcription/rna_transcription.t +4 -8
- data/tracks/perl6/exercises/robot-name/robot.t +4 -8
- data/tracks/perl6/exercises/scrabble-score/scrabble_score.t +3 -7
- data/tracks/perl6/exercises/word-count/word_count.t +3 -8
- data/tracks/r/config.json +10 -0
- data/tracks/r/docs/ABOUT.md +14 -0
- data/tracks/r/exercises/difference-of-squares/difference-of-squares.R +5 -0
- data/tracks/r/exercises/difference-of-squares/example.R +6 -0
- data/tracks/r/exercises/difference-of-squares/test_difference-of-squares.R +23 -0
- data/tracks/r/exercises/hamming/example.R +8 -0
- data/tracks/r/exercises/hamming/hamming.R +4 -0
- data/tracks/r/exercises/hamming/test_hamming.R +87 -0
- data/tracks/ruby/exercises/binary/.version +1 -1
- data/tracks/ruby/exercises/binary/binary_test.rb +17 -19
- data/tracks/ruby/exercises/binary/example.rb +13 -13
- data/tracks/ruby/exercises/isogram/.version +1 -1
- data/tracks/ruby/exercises/isogram/example.rb +1 -1
- data/tracks/ruby/exercises/isogram/isogram_test.rb +16 -30
- data/tracks/ruby/lib/binary_cases.rb +2 -3
- data/tracks/ruby/lib/isogram_cases.rb +1 -5
- data/tracks/scala/exercises/phone-number/HINTS.md +9 -0
- metadata +45 -4
@@ -0,0 +1,38 @@
|
|
1
|
+
local secret_handshake = require 'secret-handshake'
|
2
|
+
|
3
|
+
describe('secret-handshake', function()
|
4
|
+
it('should allow empty handshakes', function()
|
5
|
+
assert.are.same({}, secret_handshake(0))
|
6
|
+
end)
|
7
|
+
|
8
|
+
it('should interpret 0b1 as wink', function()
|
9
|
+
assert.are.same({ 'wink' }, secret_handshake(tonumber('1', 2)))
|
10
|
+
end)
|
11
|
+
|
12
|
+
it('should interpret 0b10 as double blink', function()
|
13
|
+
assert.are.same({ 'double blink' }, secret_handshake(tonumber('10', 2)))
|
14
|
+
end)
|
15
|
+
|
16
|
+
it('should interpret 0b100 as close your eyes', function()
|
17
|
+
assert.are.same({ 'close your eyes' }, secret_handshake(tonumber('100', 2)))
|
18
|
+
end)
|
19
|
+
|
20
|
+
it('should interpret 0b1000 as jump', function()
|
21
|
+
assert.are.same({ 'jump' }, secret_handshake(tonumber('1000', 2)))
|
22
|
+
end)
|
23
|
+
|
24
|
+
it('should allow multiple handshake primitives to be used together', function()
|
25
|
+
assert.are.same({ 'wink', 'double blink' }, secret_handshake(tonumber('11', 2)))
|
26
|
+
end)
|
27
|
+
|
28
|
+
it('should reverse the order of the primitives when 0b10000 is used', function()
|
29
|
+
assert.are.same({ 'double blink', 'wink' }, secret_handshake(tonumber('10011', 2)))
|
30
|
+
end)
|
31
|
+
|
32
|
+
it('should allow all primitives to be used together', function()
|
33
|
+
assert.are.same(
|
34
|
+
{ 'jump', 'close your eyes', 'double blink', 'wink' },
|
35
|
+
secret_handshake(tonumber('11111', 2))
|
36
|
+
)
|
37
|
+
end)
|
38
|
+
end)
|
data/tracks/ocaml/config.json
CHANGED
@@ -7,7 +7,11 @@
|
|
7
7
|
{
|
8
8
|
"slug": "hello-world",
|
9
9
|
"difficulty": 1,
|
10
|
-
"topics": [
|
10
|
+
"topics": [
|
11
|
+
"Strings",
|
12
|
+
"Optional values",
|
13
|
+
"Pattern matching"
|
14
|
+
]
|
11
15
|
},
|
12
16
|
{
|
13
17
|
"slug": "leap",
|
@@ -69,6 +73,11 @@
|
|
69
73
|
"difficulty": 3,
|
70
74
|
"topics": []
|
71
75
|
},
|
76
|
+
{
|
77
|
+
"slug": "bracket-push",
|
78
|
+
"difficulty": 4,
|
79
|
+
"topics": ["Stacks"]
|
80
|
+
},
|
72
81
|
{
|
73
82
|
"slug": "bowling",
|
74
83
|
"difficulty": 4,
|
@@ -0,0 +1,40 @@
|
|
1
|
+
open Core.Std
|
2
|
+
|
3
|
+
type 'a stack = 'a list
|
4
|
+
|
5
|
+
let push (s: 'a stack) (a: 'a): 'a stack = a :: s
|
6
|
+
let pop (s: 'a stack): ('a * 'a stack) option = match s with
|
7
|
+
| [] -> None
|
8
|
+
| x :: xs -> Some (x, xs)
|
9
|
+
|
10
|
+
(* this receives a character from the input string s.
|
11
|
+
if the character is an opening bracket, then push it on to the stack, and
|
12
|
+
return the stack (inside an Option)
|
13
|
+
if the character is a closing bracket, then pop the top of the stack, and
|
14
|
+
check the popped character matches. If it does, then return the new stack,
|
15
|
+
otherwise return None (to indicate matching failure). *)
|
16
|
+
let update (s: (char stack) option) (ch: char): (char stack) option =
|
17
|
+
match s with
|
18
|
+
| None -> None
|
19
|
+
| Some s ->
|
20
|
+
let pop_matching m = Option.filter (pop s) ~f:(fun (top, _) -> top = m)
|
21
|
+
|> Option.map ~f:snd in
|
22
|
+
match ch with
|
23
|
+
| '(' | '{' | '[' -> Some (push s ch)
|
24
|
+
| ')' -> pop_matching '('
|
25
|
+
| '}' -> pop_matching '{'
|
26
|
+
| ']' -> pop_matching '['
|
27
|
+
| _ -> Some s
|
28
|
+
|
29
|
+
(* The fold loops over the characters of s, repeatedly calling update on a stack
|
30
|
+
and each character of s.
|
31
|
+
If update ever encounters a non-matching bracket, it returns None, and the
|
32
|
+
fold will as well.
|
33
|
+
Otherwise, the fold will return a stack after going through all of the string.
|
34
|
+
If the stack is non-empty, then some non-matching brackets must remain, so the string
|
35
|
+
is not balanced.
|
36
|
+
If the stack is empty, everything matches, and the string balances.
|
37
|
+
*)
|
38
|
+
let are_balanced s =
|
39
|
+
List.fold_left (String.to_list s) ~init:(Some []) ~f:update
|
40
|
+
|> Option.exists ~f:(List.is_empty)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
open Core.Std
|
2
|
+
open OUnit2
|
3
|
+
open Bracket_push
|
4
|
+
|
5
|
+
let ae exp got _test_ctxt =
|
6
|
+
assert_equal exp got ~printer:Bool.to_string
|
7
|
+
|
8
|
+
let tests = [
|
9
|
+
"paired square brackets" >::
|
10
|
+
ae true (are_balanced "[]");
|
11
|
+
"empty string" >::
|
12
|
+
ae true (are_balanced "");
|
13
|
+
"unpaired brackets" >::
|
14
|
+
ae false (are_balanced "[[");
|
15
|
+
"wrong ordered brackets" >::
|
16
|
+
ae false (are_balanced "}{");
|
17
|
+
"paired with whitespace" >::
|
18
|
+
ae true (are_balanced "{ }");
|
19
|
+
"simple nested brackets" >::
|
20
|
+
ae true (are_balanced "{[]}");
|
21
|
+
"several paired brackets" >::
|
22
|
+
ae true (are_balanced "{}[]");
|
23
|
+
"paired and nested brackets" >::
|
24
|
+
ae true (are_balanced "([{}({}[])])");
|
25
|
+
"unopened closing brackets" >::
|
26
|
+
ae false (are_balanced "{[)][]}");
|
27
|
+
"unpaired and nested brackets" >::
|
28
|
+
ae false (are_balanced "([{])");
|
29
|
+
"paired and wrong nested brackets" >::
|
30
|
+
ae false (are_balanced "[({]})");
|
31
|
+
"math expression" >::
|
32
|
+
ae true (are_balanced "(((185 + 223.85) * 15) - 543)/2");
|
33
|
+
"complex latex expression" >::
|
34
|
+
ae true (are_balanced "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)");
|
35
|
+
]
|
36
|
+
|
37
|
+
let () =
|
38
|
+
run_test_tt_main ("bracket-push tests" >::: tests)
|
@@ -5,19 +5,19 @@ open Leap
|
|
5
5
|
let ae exp got _test_ctxt = assert_equal exp got
|
6
6
|
|
7
7
|
let tests = [
|
8
|
-
"leap year" >::
|
8
|
+
"leap year in twentieth century" >::
|
9
9
|
ae true (leap_year 1996);
|
10
|
-
"standard
|
10
|
+
"odd standard year in twentieth century" >::
|
11
11
|
ae false (leap_year 1997);
|
12
|
-
"standard
|
12
|
+
"even standard year in twentieth century" >::
|
13
13
|
ae false (leap_year 1998);
|
14
|
-
"standard nineteenth century" >::
|
14
|
+
"standard year in nineteenth century" >::
|
15
15
|
ae false (leap_year 1900);
|
16
|
-
"standard eighteenth century" >::
|
16
|
+
"standard year in eighteenth century" >::
|
17
17
|
ae false (leap_year 1800);
|
18
|
-
"leap twenty
|
18
|
+
"leap year twenty four hundred" >::
|
19
19
|
ae true (leap_year 2400);
|
20
|
-
"leap
|
20
|
+
"leap year two thousand" >::
|
21
21
|
ae true (leap_year 2000);
|
22
22
|
]
|
23
23
|
|
@@ -2,10 +2,10 @@ test: test_gen.native
|
|
2
2
|
@./all_tests.native
|
3
3
|
|
4
4
|
test_gen.native: all_tests.native src/*.ml interfaces/*.mli test/*.ml
|
5
|
-
@ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is
|
5
|
+
@ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is src,interfaces test_gen.native
|
6
6
|
|
7
7
|
all_tests.native: src/*.ml test/*.ml
|
8
|
-
@ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg oUnit -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is
|
8
|
+
@ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg oUnit -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is src,test all_tests.native
|
9
9
|
|
10
10
|
clean:
|
11
11
|
rm -rf _build
|
@@ -2,7 +2,7 @@ open Core.Std
|
|
2
2
|
|
3
3
|
open Model
|
4
4
|
|
5
|
-
type
|
5
|
+
type edit_expected_function = value: parameter -> string
|
6
6
|
|
7
7
|
type edit_parameters_function = (string * string) list -> (string * string) list
|
8
8
|
|
@@ -10,4 +10,4 @@ type subst = Subst of string
|
|
10
10
|
|
11
11
|
val subst_to_string : subst -> string
|
12
12
|
|
13
|
-
val
|
13
|
+
val fill_in_template : edit_expected_function -> edit_parameters_function -> string -> case list -> (subst list, string) Result.t
|
File without changes
|
@@ -4,6 +4,12 @@ open Model
|
|
4
4
|
type error = TopLevelMustHaveKeyCalledCases | ExpectingListOfCases |
|
5
5
|
ExpectingMapForCase | BadDescription | BadExpected
|
6
6
|
|
7
|
-
|
7
|
+
type test = {name: string; cases: case list} [@@deriving eq, show]
|
8
|
+
|
9
|
+
type tests =
|
10
|
+
| Single of case list
|
11
|
+
| Suite of test list [@@deriving eq, show]
|
12
|
+
|
13
|
+
val parse_json_text : string -> (tests, error) Result.t
|
8
14
|
|
9
15
|
val show_error : error -> string
|
@@ -2,6 +2,6 @@ open Core.Std
|
|
2
2
|
|
3
3
|
open Model
|
4
4
|
|
5
|
-
val
|
5
|
+
val edit_expected : stringify:(parameter -> string) -> slug:string -> key:string -> value:parameter -> string
|
6
6
|
|
7
|
-
val
|
7
|
+
val edit_parameters : slug: string -> (string * string) list -> (string * string) list
|
@@ -9,8 +9,12 @@ val to_list_option : json -> json list option
|
|
9
9
|
|
10
10
|
val to_list_note : 'e -> json -> ((json list, 'e) Result.t)
|
11
11
|
|
12
|
+
val to_assoc_note : 'e -> json -> ((json list, 'e) Result.t)
|
13
|
+
|
12
14
|
val to_string_note : 'e -> json -> ((string, 'e) Result.t)
|
13
15
|
|
16
|
+
val member_note : 'e -> string -> json -> ((json, 'e) Result.t)
|
17
|
+
|
14
18
|
val safe_to_int_option : json -> int option
|
15
19
|
|
16
20
|
val find_arrayi : ?start:int -> 'a array -> f:('a -> bool) -> (int * 'a) option
|
@@ -2,7 +2,7 @@ open Core.Std
|
|
2
2
|
|
3
3
|
open Model
|
4
4
|
|
5
|
-
type
|
5
|
+
type edit_expected_function = value: parameter -> string
|
6
6
|
|
7
7
|
type edit_parameters_function = (string * string) list -> (string * string) list
|
8
8
|
|
@@ -10,16 +10,20 @@ type subst = Subst of string [@@deriving eq, show]
|
|
10
10
|
|
11
11
|
let subst_to_string (Subst s) = s
|
12
12
|
|
13
|
+
let map_subst (s: subst) ~(f: string -> string): subst =
|
14
|
+
Subst (subst_to_string s |> f)
|
15
|
+
|
13
16
|
let replace_key (key: string) (value: string) (target: string): string =
|
14
17
|
let replace = String.substr_replace_all ~with_:value in
|
15
18
|
replace ~pattern:("$" ^ key) target |> replace ~pattern:("$(" ^ key ^ ")")
|
16
19
|
|
17
|
-
let rec replace_keys (f:
|
20
|
+
let rec replace_keys (f: edit_expected_function) (ed: edit_parameters_function) (s: string) (suite_name: string) (c: case): subst =
|
18
21
|
let s = replace_key "description" c.description s in
|
19
|
-
let expected = f ~
|
22
|
+
let expected = f ~value:c.expected in
|
20
23
|
let s = replace_key "expected" expected s in
|
24
|
+
let s = replace_key "suite-name" suite_name s in
|
21
25
|
let parameter_strings = ed @@ List.map ~f:(fun (k,p) -> (k,parameter_to_string p)) c.parameters in
|
22
26
|
List.fold parameter_strings ~init:(Subst s) ~f:(fun (Subst s) (k,v) -> Subst (replace_key k v s))
|
23
27
|
|
24
|
-
let
|
25
|
-
|
28
|
+
let fill_in_template (f: edit_expected_function) (ed: edit_parameters_function) test_template suite_name cases =
|
29
|
+
List.map cases ~f:(replace_keys f ed test_template suite_name)
|
@@ -21,27 +21,36 @@ let find_canonical_data_files = find_nested_files "canonical-data.json"
|
|
21
21
|
let combine_files (template_files: (string * content) list) (canonical_data_files: (string * content) list): (string * content * content) list =
|
22
22
|
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))))
|
23
23
|
|
24
|
-
let generate_code ~slug ~template_file ~canonical_data_file =
|
24
|
+
let generate_code ~(slug: string) ~(template_file: content) ~(canonical_data_file: content): (content, content) Result.t =
|
25
25
|
let template = find_template template_file in
|
26
|
-
let template = Result.of_option template ("cannot recognize file for " ^ slug ^ " as a template") in
|
27
|
-
let cases = parse_json_text canonical_data_file in
|
28
|
-
let cases = Result.map_error cases show_error in
|
29
26
|
let open Result.Monad_infix in
|
30
|
-
template >>= fun template ->
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
(
|
36
|
-
|
37
|
-
|
27
|
+
Result.of_option template ("cannot recognize file for " ^ slug ^ " as a template") >>= fun template ->
|
28
|
+
parse_json_text canonical_data_file |> Result.map_error ~f:show_error >>= (function
|
29
|
+
| Single cases ->
|
30
|
+
Result.return (fill_in_template
|
31
|
+
(edit_expected ~stringify:parameter_to_string ~slug)
|
32
|
+
(edit_parameters ~slug)
|
33
|
+
template.template
|
34
|
+
slug
|
35
|
+
cases |> fill_tests template);
|
36
|
+
| Suite tests ->
|
37
|
+
let x = List.map tests ~f:(fun {name;cases} ->
|
38
|
+
(name, fill_in_template
|
39
|
+
(edit_expected ~stringify:parameter_to_string ~slug)
|
40
|
+
(edit_parameters ~slug)
|
41
|
+
template.template
|
42
|
+
name
|
43
|
+
cases)
|
44
|
+
) in
|
45
|
+
Result.return (fill_suite template x)
|
46
|
+
)
|
38
47
|
|
39
48
|
let output_tests (files: (string * content * content) list) (output_folder: string): unit =
|
40
49
|
let output_filepath name = output_folder ^ "/" ^ name ^ "/test.ml" in
|
41
50
|
let output1 (slug,t,c) =
|
42
|
-
|
43
|
-
|
44
|
-
|
51
|
+
match generate_code slug t c with
|
52
|
+
| Ok code -> Out_channel.write_all (output_filepath slug) code
|
53
|
+
| Error e -> print_endline ("Failed when generating " ^ slug ^ ", error: " ^ e) in
|
45
54
|
List.iter files ~f:output1
|
46
55
|
|
47
56
|
let run ~(templates_folder: string) ~(canonical_data_folder: string) ~(output_folder: string) =
|
@@ -18,6 +18,12 @@ type case = {
|
|
18
18
|
expected: parameter;
|
19
19
|
} [@@deriving eq, show]
|
20
20
|
|
21
|
+
type test = {name: string; cases: case list} [@@deriving eq, show]
|
22
|
+
|
23
|
+
type tests =
|
24
|
+
| Single of case list
|
25
|
+
| Suite of test list [@@deriving eq, show]
|
26
|
+
|
21
27
|
let surround (ch: char) (s: string): string =
|
22
28
|
Char.to_string ch ^ s ^ Char.to_string ch
|
23
29
|
|
@@ -5,9 +5,8 @@ open Yojson.Safe.Util
|
|
5
5
|
open Model
|
6
6
|
|
7
7
|
type error =
|
8
|
-
|
9
|
-
BadDescription | BadExpected
|
10
|
-
[@@deriving eq]
|
8
|
+
TestMustHaveKeyCalledCases | ExpectingListOfCases | ExpectingMapForCase |
|
9
|
+
BadDescription | BadExpected | UnrecognizedJson [@@deriving eq, show]
|
11
10
|
|
12
11
|
let to_int_unsafe = function
|
13
12
|
| `Int x -> x
|
@@ -42,20 +41,48 @@ let parse_case (s: json): (case, error) Result.t = match s with
|
|
42
41
|
|
43
42
|
let parse_cases (text: string): (json, error) Result.t =
|
44
43
|
match from_string text |> member "cases" with
|
45
|
-
| `Null -> Error
|
44
|
+
| `Null -> Error TestMustHaveKeyCalledCases
|
46
45
|
| json -> Ok json
|
47
46
|
|
48
|
-
let
|
47
|
+
let parse_single (text: string): (tests, error) Result.t =
|
49
48
|
let open Result.Monad_infix in
|
50
49
|
parse_cases text >>=
|
51
50
|
to_list_note ExpectingListOfCases >>=
|
52
|
-
(sequence >> (List.map ~f:parse_case))
|
51
|
+
(sequence >> (List.map ~f:parse_case)) >>= fun ts ->
|
52
|
+
Result.return (Single ts)
|
53
|
+
|
54
|
+
let is_suite (json: json) =
|
55
|
+
let keys = List.sort (keys json) ~cmp:String.compare in
|
56
|
+
not (List.is_empty keys || keys = ["cases"] || keys = ["#"; "cases"])
|
57
|
+
|
58
|
+
let merge_result = function
|
59
|
+
| (_, Error x) -> Error x
|
60
|
+
| (n, Ok c) -> Ok {name = n; cases = c}
|
61
|
+
|
62
|
+
let parse_cases_from_suite suite =
|
63
|
+
let open Result.Monad_infix in
|
64
|
+
member_note UnrecognizedJson "cases" suite >>=
|
65
|
+
to_list_note UnrecognizedJson >>= fun tests ->
|
66
|
+
List.map tests ~f:parse_case |> sequence
|
67
|
+
|
68
|
+
let parse_json_text (text: string): (tests, error) Result.t =
|
69
|
+
let open Result.Monad_infix in
|
70
|
+
let json = from_string text in
|
71
|
+
if is_suite json
|
72
|
+
then
|
73
|
+
to_assoc_note UnrecognizedJson json >>= fun tests ->
|
74
|
+
Result.return (List.map tests ~f:(fun (name, suite) -> merge_result (name, parse_cases_from_suite suite))) >>= fun tests ->
|
75
|
+
sequence tests >>= fun tests ->
|
76
|
+
Ok (Suite tests)
|
77
|
+
else
|
78
|
+
parse_single text
|
53
79
|
|
54
80
|
let show_error = function
|
55
|
-
|
|
81
|
+
| TestMustHaveKeyCalledCases -> "Cannot parse this json - " ^
|
56
82
|
"expecting an object with a key: 'cases'"
|
57
83
|
| ExpectingMapForCase -> "Expected a json map for a test case"
|
58
84
|
| ExpectingListOfCases -> "Expected a top level map with key cases, " ^
|
59
85
|
"and a list of cases as its value."
|
60
86
|
| BadDescription -> "Case is missing a description or it is not a string."
|
61
87
|
| BadExpected -> "Case is missing an expected key or it is not a string."
|
88
|
+
| UnrecognizedJson -> "Cannot understand this json."
|
@@ -25,13 +25,20 @@ let optional_strings ~(f: string -> bool) (parameters: (string * string) list):
|
|
25
25
|
else parameter in
|
26
26
|
List.map ~f:replace parameters
|
27
27
|
|
28
|
-
let
|
29
|
-
|
|
30
|
-
|
|
28
|
+
let edit_expected ~(stringify: parameter -> string) ~(slug: string) ~(value: parameter) = match slug with
|
29
|
+
| "hamming" -> optional_int ~none:(-1) value
|
30
|
+
| "say" -> optional_int_or_string ~none:(-1) value
|
31
31
|
| _ -> stringify value
|
32
32
|
|
33
|
-
let
|
33
|
+
let edit_say (ps: (string * string) list) =
|
34
|
+
let edit = function
|
35
|
+
| ("input", v) -> ("input", if Int.of_string v < 0 then "(" ^ v ^ "L)" else v ^ "L")
|
36
|
+
| x -> x in
|
37
|
+
List.map ps ~f:edit
|
38
|
+
|
39
|
+
let edit_parameters ~(slug: string) (parameters: (string * string) list) = match (slug, parameters) with
|
34
40
|
| ("hello-world", ps) -> default_value ~key:"name" ~value:"None"
|
35
41
|
@@ optional_strings ~f:(fun _x -> true)
|
36
42
|
@@ parameters
|
43
|
+
| ("say", ps) -> edit_say ps
|
37
44
|
| (_, ps) -> ps
|