trackler 2.0.0.8 → 2.0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/bob/canonical-data.json +1 -20
  3. data/common/exercises/raindrops/canonical-data.json +18 -0
  4. data/common/exercises/sublist/canonical-data.json +5 -0
  5. data/lib/trackler/version.rb +1 -1
  6. data/tracks/clojure/config.json +5 -0
  7. data/tracks/clojure/exercises/pig-latin/project.clj +4 -0
  8. data/tracks/clojure/exercises/pig-latin/src/example.clj +49 -0
  9. data/tracks/clojure/exercises/pig-latin/test/pig_latin_test.clj +92 -0
  10. data/tracks/clojure/exercises/robot-name/src/example.clj +8 -11
  11. data/tracks/clojure/exercises/robot-name/test/robot_name_test.clj +23 -18
  12. data/tracks/crystal/config.json +6 -0
  13. data/tracks/crystal/exercises/acronym/spec/acronym_spec.cr +7 -7
  14. data/tracks/crystal/exercises/forth/spec/forth_spec.cr +198 -0
  15. data/tracks/crystal/exercises/forth/src/example.cr +187 -0
  16. data/tracks/crystal/exercises/hello-world/spec/hello_world_spec.cr +3 -3
  17. data/tracks/crystal/src/generator/exercises/acronym.cr +1 -1
  18. data/tracks/crystal/src/generator/exercises/exercise_generator.cr +3 -2
  19. data/tracks/crystal/src/generator/exercises/forth.cr +56 -0
  20. data/tracks/crystal/src/generator/exercises/templates/example.tt +2 -2
  21. data/tracks/crystal/src/generator/spec/exercise_generator_spec.cr +5 -3
  22. data/tracks/csharp/exercises/wordy/WordyTest.cs +2 -2
  23. data/tracks/elixir/config.json +83 -70
  24. data/tracks/fsharp/exercises/wordy/WordyTest.fs +1 -1
  25. data/tracks/go/config.json +28 -3
  26. data/tracks/go/exercises/all-your-base/all_your_base_test.go +185 -0
  27. data/tracks/go/exercises/all-your-base/example.go +60 -0
  28. data/tracks/go/exercises/isogram/example.go +15 -0
  29. data/tracks/go/exercises/isogram/isogram_test.go +50 -0
  30. data/tracks/go/exercises/ledger/ledger.go +2 -2
  31. data/tracks/go/exercises/pangram/example.go +32 -0
  32. data/tracks/go/exercises/pangram/pangram_test.go +43 -0
  33. data/tracks/go/exercises/protein-translation/example.go +59 -0
  34. data/tracks/go/exercises/protein-translation/protein_translation_test.go +69 -0
  35. data/tracks/go/exercises/tree-building/tree_building.go +1 -1
  36. data/tracks/go/exercises/twelve-days/example.go +57 -0
  37. data/tracks/go/exercises/twelve-days/twelve_days_test.go +79 -0
  38. data/tracks/haskell/.travis.yml +13 -8
  39. data/tracks/haskell/config.json +6 -0
  40. data/tracks/haskell/exercises/accumulate/stack.yaml +1 -1
  41. data/tracks/haskell/exercises/all-your-base/stack.yaml +1 -1
  42. data/tracks/haskell/exercises/allergies/stack.yaml +1 -1
  43. data/tracks/haskell/exercises/alphametics/stack.yaml +1 -1
  44. data/tracks/haskell/exercises/anagram/stack.yaml +1 -1
  45. data/tracks/haskell/exercises/atbash-cipher/stack.yaml +1 -1
  46. data/tracks/haskell/exercises/bank-account/stack.yaml +1 -1
  47. data/tracks/haskell/exercises/beer-song/stack.yaml +1 -1
  48. data/tracks/haskell/exercises/binary/stack.yaml +1 -1
  49. data/tracks/haskell/exercises/binary-search-tree/stack.yaml +1 -1
  50. data/tracks/haskell/exercises/bob/stack.yaml +1 -1
  51. data/tracks/haskell/exercises/bowling/HINTS.md +19 -0
  52. data/tracks/haskell/exercises/bowling/examples/success-standard/package.yaml +16 -0
  53. data/tracks/haskell/exercises/bowling/examples/success-standard/src/Bowling.hs +84 -0
  54. data/tracks/haskell/exercises/bowling/package.yaml +19 -0
  55. data/tracks/haskell/exercises/bowling/src/Bowling.hs +9 -0
  56. data/tracks/haskell/exercises/bowling/stack.yaml +1 -0
  57. data/tracks/haskell/exercises/bowling/test/Tests.hs +143 -0
  58. data/tracks/haskell/exercises/change/stack.yaml +1 -1
  59. data/tracks/haskell/exercises/clock/stack.yaml +1 -1
  60. data/tracks/haskell/exercises/connect/stack.yaml +1 -1
  61. data/tracks/haskell/exercises/crypto-square/stack.yaml +1 -1
  62. data/tracks/haskell/exercises/custom-set/stack.yaml +1 -1
  63. data/tracks/haskell/exercises/difference-of-squares/stack.yaml +1 -1
  64. data/tracks/haskell/exercises/dominoes/stack.yaml +1 -1
  65. data/tracks/haskell/exercises/etl/stack.yaml +1 -1
  66. data/tracks/haskell/exercises/food-chain/stack.yaml +1 -1
  67. data/tracks/haskell/exercises/forth/stack.yaml +1 -1
  68. data/tracks/haskell/exercises/gigasecond/stack.yaml +1 -1
  69. data/tracks/haskell/exercises/go-counting/stack.yaml +1 -1
  70. data/tracks/haskell/exercises/grade-school/stack.yaml +1 -1
  71. data/tracks/haskell/exercises/grains/stack.yaml +1 -1
  72. data/tracks/haskell/exercises/hamming/stack.yaml +1 -1
  73. data/tracks/haskell/exercises/hexadecimal/stack.yaml +1 -1
  74. data/tracks/haskell/exercises/house/stack.yaml +1 -1
  75. data/tracks/haskell/exercises/kindergarten-garden/stack.yaml +1 -1
  76. data/tracks/haskell/exercises/largest-series-product/stack.yaml +1 -1
  77. data/tracks/haskell/exercises/leap/stack.yaml +1 -1
  78. data/tracks/haskell/exercises/lens-person/stack.yaml +1 -1
  79. data/tracks/haskell/exercises/linked-list/stack.yaml +1 -1
  80. data/tracks/haskell/exercises/list-ops/stack.yaml +1 -1
  81. data/tracks/haskell/exercises/luhn/stack.yaml +1 -1
  82. data/tracks/haskell/exercises/matrix/stack.yaml +1 -1
  83. data/tracks/haskell/exercises/meetup/stack.yaml +1 -1
  84. data/tracks/haskell/exercises/minesweeper/stack.yaml +1 -1
  85. data/tracks/haskell/exercises/nth-prime/stack.yaml +1 -1
  86. data/tracks/haskell/exercises/nucleotide-count/stack.yaml +1 -1
  87. data/tracks/haskell/exercises/ocr-numbers/stack.yaml +1 -1
  88. data/tracks/haskell/exercises/octal/stack.yaml +1 -1
  89. data/tracks/haskell/exercises/palindrome-products/stack.yaml +1 -1
  90. data/tracks/haskell/exercises/parallel-letter-frequency/stack.yaml +1 -1
  91. data/tracks/haskell/exercises/pascals-triangle/stack.yaml +1 -1
  92. data/tracks/haskell/exercises/phone-number/stack.yaml +1 -1
  93. data/tracks/haskell/exercises/pig-latin/stack.yaml +1 -1
  94. data/tracks/haskell/exercises/pov/stack.yaml +1 -1
  95. data/tracks/haskell/exercises/prime-factors/stack.yaml +1 -1
  96. data/tracks/haskell/exercises/pythagorean-triplet/stack.yaml +1 -1
  97. data/tracks/haskell/exercises/queen-attack/stack.yaml +1 -1
  98. data/tracks/haskell/exercises/raindrops/stack.yaml +1 -1
  99. data/tracks/haskell/exercises/rna-transcription/stack.yaml +1 -1
  100. data/tracks/haskell/exercises/robot-name/stack.yaml +1 -1
  101. data/tracks/haskell/exercises/robot-simulator/stack.yaml +1 -1
  102. data/tracks/haskell/exercises/roman-numerals/stack.yaml +1 -1
  103. data/tracks/haskell/exercises/saddle-points/stack.yaml +1 -1
  104. data/tracks/haskell/exercises/say/stack.yaml +1 -1
  105. data/tracks/haskell/exercises/scrabble-score/stack.yaml +1 -1
  106. data/tracks/haskell/exercises/secret-handshake/stack.yaml +1 -1
  107. data/tracks/haskell/exercises/series/stack.yaml +1 -1
  108. data/tracks/haskell/exercises/sgf-parsing/stack.yaml +1 -1
  109. data/tracks/haskell/exercises/sieve/stack.yaml +1 -1
  110. data/tracks/haskell/exercises/simple-cipher/stack.yaml +1 -1
  111. data/tracks/haskell/exercises/simple-linked-list/stack.yaml +1 -1
  112. data/tracks/haskell/exercises/space-age/stack.yaml +1 -1
  113. data/tracks/haskell/exercises/strain/stack.yaml +1 -1
  114. data/tracks/haskell/exercises/sublist/stack.yaml +1 -1
  115. data/tracks/haskell/exercises/sum-of-multiples/stack.yaml +1 -1
  116. data/tracks/haskell/exercises/triangle/stack.yaml +1 -1
  117. data/tracks/haskell/exercises/trinary/stack.yaml +1 -1
  118. data/tracks/haskell/exercises/word-count/stack.yaml +1 -1
  119. data/tracks/haskell/exercises/wordy/stack.yaml +1 -1
  120. data/tracks/haskell/exercises/zebra-puzzle/stack.yaml +1 -1
  121. data/tracks/haskell/exercises/zipper/stack.yaml +1 -1
  122. data/tracks/java/config.json +13 -1
  123. data/tracks/java/exercises/etl/src/main/java/Etl.java +3 -3
  124. data/tracks/java/exercises/hello-world/GETTING_STARTED.md +1 -1
  125. data/tracks/java/exercises/hello-world/src/main/java/HelloWorld.java +3 -3
  126. data/tracks/java/exercises/minesweeper/build.gradle +17 -0
  127. data/tracks/java/exercises/minesweeper/src/example/java/MinesweeperBoard.java +111 -0
  128. data/tracks/java/exercises/minesweeper/src/main/java/MinesweeperBoard.java +5 -0
  129. data/tracks/java/exercises/minesweeper/src/test/java/MinesweeperBoardTest.java +295 -0
  130. data/tracks/java/exercises/nucleotide-count/src/test/java/NucleotideTest.java +67 -67
  131. data/tracks/java/exercises/series/build.gradle +18 -0
  132. data/tracks/java/exercises/series/src/example/java/Series.java +39 -0
  133. data/tracks/java/exercises/series/src/main/java/.keep +0 -0
  134. data/tracks/java/exercises/series/src/main/java/Series.java +3 -0
  135. data/tracks/java/exercises/series/src/test/java/.keep +0 -0
  136. data/tracks/java/exercises/series/src/test/java/SeriesTest.java +154 -0
  137. data/tracks/java/exercises/settings.gradle +2 -0
  138. data/tracks/javascript/exercises/custom-set/custom-set.spec.js +130 -84
  139. data/tracks/javascript/exercises/custom-set/example-gen.js +200 -0
  140. data/tracks/ocaml/Makefile +5 -1
  141. data/tracks/ocaml/config.json +2 -1
  142. data/tracks/ocaml/exercises/anagram/test.ml +35 -24
  143. data/tracks/ocaml/exercises/bob/example.ml +1 -1
  144. data/tracks/ocaml/exercises/bob/test.ml +53 -40
  145. data/tracks/ocaml/exercises/hamming/test.ml +41 -31
  146. data/tracks/ocaml/exercises/raindrops/test.ml +38 -39
  147. data/tracks/ocaml/tools/test-generator/.merlin +5 -0
  148. data/tracks/ocaml/tools/test-generator/Makefile +15 -0
  149. data/tracks/ocaml/tools/test-generator/_tags +0 -0
  150. data/tracks/ocaml/tools/test-generator/src/codegen.ml +17 -0
  151. data/tracks/ocaml/tools/test-generator/src/codegen.mli +7 -0
  152. data/tracks/ocaml/tools/test-generator/src/leap.json +39 -0
  153. data/tracks/ocaml/tools/test-generator/src/model.ml +31 -0
  154. data/tracks/ocaml/tools/test-generator/src/parser.ml +61 -0
  155. data/tracks/ocaml/tools/test-generator/src/parser.mli +9 -0
  156. data/tracks/ocaml/tools/test-generator/src/special_cases.ml +12 -0
  157. data/tracks/ocaml/tools/test-generator/src/special_cases.mli +7 -0
  158. data/tracks/ocaml/tools/test-generator/src/test_gen.ml +25 -0
  159. data/tracks/ocaml/tools/test-generator/src/test_generator.ml +62 -0
  160. data/tracks/ocaml/tools/test-generator/src/test_generator.mli +6 -0
  161. data/tracks/ocaml/tools/test-generator/src/utils.ml +32 -0
  162. data/tracks/ocaml/tools/test-generator/src/utils.mli +18 -0
  163. data/tracks/ocaml/tools/test-generator/templates/anagram/template.ml +17 -0
  164. data/tracks/ocaml/tools/test-generator/templates/bob/template.ml +15 -0
  165. data/tracks/ocaml/tools/test-generator/templates/hamming/template.ml +30 -0
  166. data/tracks/ocaml/tools/test-generator/templates/leap/template.ml +15 -0
  167. data/tracks/ocaml/tools/test-generator/templates/raindrops/template.ml +15 -0
  168. data/tracks/ocaml/tools/test-generator/templates/word-count/template.ml +19 -0
  169. data/tracks/ocaml/tools/test-generator/test/all_tests.ml +11 -0
  170. data/tracks/ocaml/tools/test-generator/test/codegen_test.ml +20 -0
  171. data/tracks/ocaml/tools/test-generator/test/model_test.ml +27 -0
  172. data/tracks/ocaml/tools/test-generator/test/parser_test.ml +73 -0
  173. data/tracks/ocaml/tools/test-generator/test/special_cases_test.ml +22 -0
  174. data/tracks/ocaml/tools/test-generator/test/test_generator_test.ml +11 -0
  175. data/tracks/ocaml/tools/test-generator/test/utils_test.ml +21 -0
  176. data/tracks/perl5/config.json +1 -1
  177. data/tracks/perl6/accumulate/accumulate.t +8 -2
  178. data/tracks/perl6/anagram/Example.pm +1 -1
  179. data/tracks/perl6/anagram/anagram.t +7 -8
  180. data/tracks/perl6/binary/Example.pm +1 -1
  181. data/tracks/perl6/binary/binary.t +7 -8
  182. data/tracks/perl6/bob/bob.t +1 -3
  183. data/tracks/perl6/config.json +1 -0
  184. data/tracks/perl6/grains/grains.t +7 -2
  185. data/tracks/perl6/leap/leap.t +3 -1
  186. data/tracks/perl6/raindrops/raindrops.t +8 -2
  187. data/tracks/perl6/rna-transcription/rna_transcription.t +8 -9
  188. data/tracks/perl6/robot-name/robot.t +8 -9
  189. data/tracks/perl6/scrabble-score/Example.pm +1 -1
  190. data/tracks/perl6/scrabble-score/scrabble_score.t +8 -2
  191. data/tracks/perl6/word-count/word_count.t +8 -2
  192. data/tracks/php/config.json +5 -0
  193. data/tracks/php/exercises/markdown/example.php +85 -0
  194. data/tracks/php/exercises/markdown/markdown.php +82 -0
  195. data/tracks/php/exercises/markdown/markdown_test.php +57 -0
  196. data/tracks/python/exercises/hamming/example.py +3 -0
  197. data/tracks/python/exercises/hamming/hamming_test.py +40 -14
  198. data/tracks/python/exercises/rna-transcription/example.py +6 -1
  199. data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +9 -0
  200. data/tracks/ruby/config.json +6 -0
  201. data/tracks/ruby/exercises/dominoes/.version +1 -0
  202. data/tracks/ruby/exercises/dominoes/dominoes_test.rb +149 -0
  203. data/tracks/ruby/exercises/dominoes/example.rb +37 -0
  204. data/tracks/ruby/exercises/dominoes/example.tt +57 -0
  205. data/tracks/ruby/exercises/pangram/.version +1 -1
  206. data/tracks/ruby/exercises/pangram/example.rb +2 -2
  207. data/tracks/ruby/exercises/pangram/example.tt +5 -7
  208. data/tracks/ruby/exercises/pangram/pangram_test.rb +30 -25
  209. data/tracks/ruby/exercises/queen-attack/.version +1 -0
  210. data/tracks/ruby/exercises/queen-attack/example.rb +5 -30
  211. data/tracks/ruby/exercises/queen-attack/example.tt +22 -0
  212. data/tracks/ruby/exercises/queen-attack/queen_attack_test.rb +46 -95
  213. data/tracks/ruby/exercises/triangle/.version +1 -0
  214. data/tracks/ruby/exercises/triangle/example.rb +15 -22
  215. data/tracks/ruby/exercises/triangle/example.tt +20 -0
  216. data/tracks/ruby/exercises/triangle/triangle_test.rb +80 -40
  217. data/tracks/ruby/lib/dominoes_cases.rb +23 -0
  218. data/tracks/ruby/lib/pangram_cases.rb +19 -4
  219. data/tracks/ruby/lib/queen_attack_cases.rb +54 -0
  220. data/tracks/ruby/lib/triangle_cases.rb +51 -0
  221. data/tracks/scala/config.json +6 -0
  222. data/tracks/scala/exercises/dominoes/Example.scala +41 -0
  223. data/tracks/scala/exercises/dominoes/build.sbt +3 -0
  224. data/tracks/scala/exercises/dominoes/src/main/scala/Dominoes.scala +4 -0
  225. data/tracks/scala/exercises/dominoes/src/test/scala/DominoesSuite.scala +91 -0
  226. metadata +83 -2
@@ -4,45 +4,58 @@ open Bob
4
4
 
5
5
  let ae exp got _test_ctxt = assert_equal ~printer:String.to_string exp got
6
6
 
7
- let tests =
8
- ["something">::
9
- ae "Whatever." (response_for "Tom-ay-to, tom-aaaah-to.");
10
- "shouts">::
11
- ae "Whoa, chill out!" (response_for "WATCH OUT!");
12
- "questions">::
13
- ae "Sure." (response_for "Does this cryogenic chamber make me look fat?");
14
- "forceful talking">::
15
- ae "Whatever." (response_for "Let's go make out behind the gym!");
16
- "acronyms">::
17
- ae "Whatever." (response_for "It's ok if you don't want to go to the DMV.");
18
- "forceful questions">::
19
- ae "Whoa, chill out!" (response_for "WHAT THE HELL WERE YOU THINKING?");
20
- "shouting with special characters">::
21
- ae "Whoa, chill out!"
22
- (response_for "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!");
23
- "shouting numbers">::
24
- ae "Whoa, chill out!" (response_for "1, 2, 3, GO!");
25
- "statement containing question mark">::
26
- ae "Whatever." (response_for "Ending with ? means a question.");
27
- "silence">::
28
- ae "Fine. Be that way!" (response_for "");
29
- "prolonged silence">::
30
- ae "Fine. Be that way!" (response_for " ");
31
- "non-letters with question">::
32
- ae "Sure." (response_for ":) ?");
33
- "multiple line questons">::
34
- ae "Whatever."
35
- (response_for "\nDoes this cryogenic chamber make me look fat? \nno");
36
- "other whitespace">::
37
- (* No unicode whitespace as OCaml Core doesn't seem to handle Unicode.
38
- * Not it seems does it see ASCII 11 (\v) as whitespace.
39
- *)
40
- ae "Fine. Be that way!" (response_for "\n\r \t");
41
- "only numbers">::
42
- ae "Whatever." (response_for "1, 2, 3");
43
- "question with only numbers">::
44
- ae "Sure." (response_for "4?");
45
- ]
7
+ let tests = [
8
+ "stating something" >::
9
+ ae "Whatever." (response_for "Tom-ay-to, tom-aaaah-to.");
10
+ "shouting" >::
11
+ ae "Whoa, chill out!" (response_for "WATCH OUT!");
12
+ "shouting gibberish" >::
13
+ ae "Whoa, chill out!" (response_for "FCECDFCAAB");
14
+ "asking a question" >::
15
+ ae "Sure." (response_for "Does this cryogenic chamber make me look fat?");
16
+ "asking a numeric question" >::
17
+ ae "Sure." (response_for "You are, what, like 15?");
18
+ "asking gibberish" >::
19
+ ae "Sure." (response_for "fffbbcbeab?");
20
+ "talking forcefully" >::
21
+ ae "Whatever." (response_for "Let's go make out behind the gym!");
22
+ "using acronyms in regular speech" >::
23
+ ae "Whatever." (response_for "It's OK if you don't want to go to the DMV.");
24
+ "forceful question" >::
25
+ ae "Whoa, chill out!" (response_for "WHAT THE HELL WERE YOU THINKING?");
26
+ "shouting numbers" >::
27
+ ae "Whoa, chill out!" (response_for "1, 2, 3 GO!");
28
+ "only numbers" >::
29
+ ae "Whatever." (response_for "1, 2, 3");
30
+ "question with only numbers" >::
31
+ ae "Sure." (response_for "4?");
32
+ "shouting with special characters" >::
33
+ ae "Whoa, chill out!" (response_for "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!");
34
+ "shouting with no exclamation mark" >::
35
+ ae "Whoa, chill out!" (response_for "I HATE YOU");
36
+ "statement containing question mark" >::
37
+ ae "Whatever." (response_for "Ending with ? means a question.");
38
+ "non-letters with question" >::
39
+ ae "Sure." (response_for ":) ?");
40
+ "prattling on" >::
41
+ ae "Sure." (response_for "Wait! Hang on. Are you going to be OK?");
42
+ "silence" >::
43
+ ae "Fine. Be that way!" (response_for "");
44
+ "prolonged silence" >::
45
+ ae "Fine. Be that way!" (response_for " ");
46
+ "alternate silence" >::
47
+ ae "Fine. Be that way!" (response_for "\t\t\t\t\t\t\t\t\t\t");
48
+ "multiple line question" >::
49
+ ae "Whatever." (response_for "\nDoes this cryogenic chamber make me look fat?\nno");
50
+ "starting with whitespace" >::
51
+ ae "Whatever." (response_for " hmmmmmmm...");
52
+ "ending with whitespace" >::
53
+ ae "Sure." (response_for "Okay if like my spacebar quite a bit? ");
54
+ "other whitespace" >::
55
+ ae "Fine. Be that way!" (response_for "\n\r \t");
56
+ "non-question ending with whitespace" >::
57
+ ae "Whatever." (response_for "This is a statement ending with whitespace ");
58
+ ]
46
59
 
47
60
  let () =
48
- run_test_tt_main ("bob tests" >::: tests)
61
+ run_test_tt_main ("bob tests" >::: tests)
@@ -8,39 +8,49 @@ let printer n =
8
8
  let ae exp got _test_ctxt = assert_equal ~printer exp got
9
9
 
10
10
  let dna_of_string s =
11
- let open Hamming in
12
- let f = function
13
- | 'A' -> A
14
- | 'C' -> C
15
- | 'G' -> G
16
- | 'T' -> T
17
- | _ -> failwith "Big news! New nucleotide discovered" in
18
- String.to_list s |> List.map ~f
11
+ let open Hamming in
12
+ let f = function
13
+ | 'A' -> A
14
+ | 'C' -> C
15
+ | 'G' -> G
16
+ | 'T' -> T
17
+ | _ -> failwith "Big news! New nucleotide discovered" in
18
+ String.to_list s |> List.map ~f
19
19
 
20
20
  let hamdist a b = Hamming.hamming_distance (dna_of_string a) (dna_of_string b)
21
21
 
22
- let tests =
23
- ["no difference between empty strands">::
24
- ae (Some 0) (hamdist "" "");
25
- "no difference between identical strands">::
26
- ae (Some 0) (hamdist "GGACTAGA"
27
- "GGACTAGA");
28
- "hamming distance in off by one strand">::
29
- ae (Some 19) (hamdist "GGACGGATTCTGACCTGGACTAATTTTGGGGG"
30
- "AGGACGGATTCTGACCTGGACTAATTTTGGGG");
31
- "small hamming distance in middle somewhere">::
32
- ae (Some 1) (hamdist "GGACG"
33
- "GGTCG");
34
- "larger distance">::
35
- ae (Some 2) (hamdist "ACCAGGG"
36
- "ACTATGG");
37
- "disallow first strand longer">::
38
- ae None (hamdist "GACTACGGACAGGGTAGGGAAT"
39
- "GACATCGCACACC");
40
- "disallow second strand longer">::
41
- ae None (hamdist "AAACTAGGGG"
42
- "AGGCTAGCGGTAGGAC")
43
- ]
22
+ let tests = [
23
+ "identical strands" >::
24
+ ae (Some 0) (hamdist "A" "A");
25
+ "long identical strands" >::
26
+ ae (Some 0) (hamdist "GGACTGA" "GGACTGA");
27
+ "complete distance in single nucleotide strands" >::
28
+ ae (Some 1) (hamdist "A" "G");
29
+ "complete distance in small strands" >::
30
+ ae (Some 2) (hamdist "AG" "CT");
31
+ "small distance in small strands" >::
32
+ ae (Some 1) (hamdist "AT" "CT");
33
+ "small distance" >::
34
+ ae (Some 1) (hamdist "GGACG" "GGTCG");
35
+ "small distance in long strands" >::
36
+ ae (Some 2) (hamdist "ACCAGGG" "ACTATGG");
37
+ "non-unique character in first strand" >::
38
+ ae (Some 1) (hamdist "AGA" "AGG");
39
+ "non-unique character in second strand" >::
40
+ ae (Some 1) (hamdist "AGG" "AGA");
41
+ "same nucleotides in different positions" >::
42
+ ae (Some 2) (hamdist "TAG" "GAT");
43
+ "large distance" >::
44
+ ae (Some 4) (hamdist "GATACA" "GCATAA");
45
+ "large distance in off-by-one strand" >::
46
+ ae (Some 9) (hamdist "GGACGGATTCTG" "AGGACGGATTCT");
47
+ "empty strands" >::
48
+ ae (Some 0) (hamdist "" "");
49
+ "disallow first strand longer" >::
50
+ ae None (hamdist "AATG" "AAA");
51
+ "disallow second strand longer" >::
52
+ ae None (hamdist "ATA" "AGTG");
53
+ ]
44
54
 
45
55
  let () =
46
- run_test_tt_main ("point-mutations tests" >::: tests)
56
+ run_test_tt_main ("hamming tests" >::: tests)
@@ -4,45 +4,44 @@ open Raindrops
4
4
 
5
5
  let ae exp got _test_ctxt = assert_equal ~printer:Fn.id exp got
6
6
 
7
- let tests =
8
- [
9
- "raindrop 1">::
10
- ae "1" (raindrop 1);
11
- "raindrop 3">::
12
- ae "Pling" (raindrop 3);
13
- "raindrop 5">::
14
- ae "Plang" (raindrop 5);
15
- "raindrop 7">::
16
- ae "Plong" (raindrop 7);
17
- "raindrop 6">::
18
- ae "Pling" (raindrop 6);
19
- "raindrop 8">::
20
- ae "8" (raindrop 8);
21
- "raindrop 9">::
22
- ae "Pling" (raindrop 9);
23
- "raindrop 10">::
24
- ae "Plang" (raindrop 10);
25
- "raindrop 14">::
26
- ae "Plong" (raindrop 14);
27
- "raindrop 15">::
28
- ae "PlingPlang" (raindrop 15);
29
- "raindrop 21">::
30
- ae "PlingPlong" (raindrop 21);
31
- "raindrop 25">::
32
- ae "Plang" (raindrop 25);
33
- "raindrop 27">::
34
- ae "Pling" (raindrop 27);
35
- "raindrop 35">::
36
- ae "PlangPlong" (raindrop 35);
37
- "raindrop 49">::
38
- ae "Plong" (raindrop 49);
39
- "raindrop 52">::
40
- ae "52" (raindrop 52);
41
- "raindrop 105">::
42
- ae "PlingPlangPlong" (raindrop 105);
43
- "raindrop 3125">::
44
- ae "Plang" (raindrop 3125);
7
+ let tests = [
8
+ "the sound for 1 is 1" >::
9
+ ae "1" (raindrop 1);
10
+ "the sound for 3 is Pling" >::
11
+ ae "Pling" (raindrop 3);
12
+ "the sound for 5 is Plang" >::
13
+ ae "Plang" (raindrop 5);
14
+ "the sound for 7 is Plong" >::
15
+ ae "Plong" (raindrop 7);
16
+ "the sound for 6 is Pling as it has a factor 3" >::
17
+ ae "Pling" (raindrop 6);
18
+ "2 to the power 3 does not make a raindrop sound as 3 is the exponent not the base" >::
19
+ ae "8" (raindrop 8);
20
+ "the sound for 9 is Pling as it has a factor 3" >::
21
+ ae "Pling" (raindrop 9);
22
+ "the sound for 10 is Plang as it has a factor 5" >::
23
+ ae "Plang" (raindrop 10);
24
+ "the sound for 14 is Plong as it has a factor of 7" >::
25
+ ae "Plong" (raindrop 14);
26
+ "the sound for 15 is PlingPlang as it has factors 3 and 5" >::
27
+ ae "PlingPlang" (raindrop 15);
28
+ "the sound for 21 is PlingPlong as it has factors 3 and 7" >::
29
+ ae "PlingPlong" (raindrop 21);
30
+ "the sound for 25 is Plang as it has a factor 5" >::
31
+ ae "Plang" (raindrop 25);
32
+ "the sound for 27 is Pling as it has a factor 3" >::
33
+ ae "Pling" (raindrop 27);
34
+ "the sound for 35 is PlangPlong as it has factors 5 and 7" >::
35
+ ae "PlangPlong" (raindrop 35);
36
+ "the sound for 49 is Plong as it has a factor 7" >::
37
+ ae "Plong" (raindrop 49);
38
+ "the sound for 52 is 52" >::
39
+ ae "52" (raindrop 52);
40
+ "the sound for 105 is PlingPlangPlong as it has factors 3, 5 and 7" >::
41
+ ae "PlingPlangPlong" (raindrop 105);
42
+ "the sound for 3125 is Plang as it has a factor 5" >::
43
+ ae "Plang" (raindrop 3125);
45
44
  ]
46
45
 
47
46
  let () =
48
- run_test_tt_main ("raindrops tests" >::: tests)
47
+ run_test_tt_main ("raindrops tests" >::: tests)
@@ -0,0 +1,5 @@
1
+ S src/**
2
+ S test/**
3
+ B _build/src
4
+ B _build/test
5
+ PKG core oUnit yojson
@@ -0,0 +1,15 @@
1
+ test: test_gen.native
2
+ @./all_tests.native
3
+
4
+ test_gen.native: all_tests.native
5
+ @ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg yojson -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is "src" test_gen.native
6
+
7
+ all_tests.native: src/*.ml src/*.mli test/*.ml
8
+ @ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg oUnit -pkg yojson -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is "src,test" all_tests.native
9
+
10
+ clean:
11
+ rm -rf _build
12
+ rm -f test_gen.native
13
+ rm -f all_tests.native
14
+
15
+ .PHONY: clean
File without changes
@@ -0,0 +1,17 @@
1
+ open Core.Std
2
+
3
+ open Model
4
+
5
+ type fixup_function = key: string -> value: parameter -> string
6
+
7
+ let replace_key (key: string) (value: string) (target: string): string =
8
+ String.substr_replace_all target ~pattern:("$" ^ key) ~with_:value
9
+
10
+ let rec replace_keys (f: fixup_function) (s: string) (c: case): string =
11
+ let s = replace_key "name" c.name s in
12
+ let expected = f ~key:"expected" ~value:c.expected in
13
+ let s = replace_key "expected" expected s in
14
+ List.fold c.parameters ~init:s ~f:(fun s (k,v) -> replace_key k (parameter_to_string v) s)
15
+
16
+ let generate_code (f: fixup_function) template cases =
17
+ Ok (List.map cases ~f:(replace_keys f template))
@@ -0,0 +1,7 @@
1
+ open Core.Std
2
+
3
+ open Model
4
+
5
+ type fixup_function = key: string -> value: parameter -> string
6
+
7
+ val generate_code : fixup_function -> string -> case list -> (string list, string) Result.t
@@ -0,0 +1,39 @@
1
+ {
2
+ "cases": [
3
+ {
4
+ "description": "leap year",
5
+ "input": 1996,
6
+ "expected": true
7
+ },
8
+ {
9
+ "description": "standard and odd year",
10
+ "input": 1997,
11
+ "expected": false
12
+ },
13
+ {
14
+ "description": "standard even year",
15
+ "input": 1998,
16
+ "expected": false
17
+ },
18
+ {
19
+ "description": "standard nineteenth century",
20
+ "input": 1900,
21
+ "expected": false
22
+ },
23
+ {
24
+ "description": "standard eighteenth century",
25
+ "input": 1800,
26
+ "expected": false
27
+ },
28
+ {
29
+ "description": "leap twenty fourth century",
30
+ "input": 2400,
31
+ "expected": true
32
+ },
33
+ {
34
+ "description": "leap y2k",
35
+ "input": 2000,
36
+ "expected": true
37
+ }
38
+ ]
39
+ }
@@ -0,0 +1,31 @@
1
+ open Core.Std
2
+
3
+ open Utils
4
+
5
+ type parameter =
6
+ | String of string
7
+ | Float of float
8
+ | Int of int
9
+ | Bool of bool
10
+ | StringList of (string list)
11
+ | IntStringMap of ((string * int) list) [@@deriving eq, show]
12
+
13
+ type 'a elements = (string * 'a) list [@@deriving eq, show]
14
+
15
+ type case = {
16
+ name: string;
17
+ parameters: parameter elements;
18
+ expected: parameter;
19
+ } [@@deriving eq, show]
20
+
21
+ let surround (ch: char) (s: string): string =
22
+ Char.to_string ch ^ s ^ Char.to_string ch
23
+
24
+ let parameter_to_string = function
25
+ | String s -> String.escaped s
26
+ | Float f -> Float.to_string f
27
+ | Int n -> Int.to_string n
28
+ | Bool b -> Bool.to_string b
29
+ | StringList xs -> "[" ^ String.concat ~sep:"; " (List.map ~f:(surround '\"' >> String.escaped) xs) ^ "]"
30
+ | IntStringMap xs -> "[" ^ String.concat ~sep:"; "
31
+ (List.map xs ~f:(fun (k,v) -> "(\"" ^ String.escaped k ^ "\", " ^ Int.to_string v ^ ")")) ^ "]"
@@ -0,0 +1,61 @@
1
+ open Core.Std
2
+ open Utils
3
+ open Yojson.Safe
4
+ open Yojson.Safe.Util
5
+ open Model
6
+
7
+ type error =
8
+ TopLevelMustHaveKeyCalledCases | ExpectingListOfCases | ExpectingMapForCase |
9
+ BadDescription | BadExpected
10
+ [@@deriving eq]
11
+
12
+ let to_int_unsafe = function
13
+ | `Int x -> x
14
+ | _ -> failwith "need an int here"
15
+
16
+ let to_parameter (s: json) = match s with
17
+ | `String x -> Some (String x)
18
+ | `Float x -> Some (Float x)
19
+ | `Int x -> Some (Int x)
20
+ | `Bool x -> Some (Bool x)
21
+ | `List x -> Some (StringList (List.map x ~f:to_string))
22
+ | `Assoc x -> Some (IntStringMap (List.map x ~f:(fun (k,v) -> (k,to_int_unsafe v))))
23
+ | _ -> None
24
+
25
+ let parse_parameters (parameters: (string * json) list): parameter elements =
26
+ List.filter_map parameters ~f:(fun (k, v) -> Option.map ~f:(fun v -> (k, v)) (to_parameter v))
27
+
28
+ let parse_case_assoc (parameters: (string * json) list): (case, error) Result.t =
29
+ let find name e = List.Assoc.find parameters name |> Result.of_option ~error:e in
30
+ let test_parameters = List.Assoc.remove parameters "description" in
31
+ let test_parameters = List.Assoc.remove test_parameters "expected" in
32
+ let open Result.Monad_infix in
33
+ find "description" BadDescription >>=
34
+ to_string_note BadDescription >>= fun description ->
35
+ find "expected" BadExpected >>= fun expectedJson ->
36
+ to_parameter expectedJson |> Result.of_option ~error:BadExpected >>= fun expected ->
37
+ Ok {name = description; parameters = parse_parameters test_parameters; expected = expected}
38
+
39
+ let parse_case (s: json): (case, error) Result.t = match s with
40
+ | `Assoc assoc -> parse_case_assoc assoc
41
+ | _ -> Error ExpectingMapForCase
42
+
43
+ let parse_cases (text: string): (json, error) Result.t =
44
+ match from_string text |> member "cases" with
45
+ | `Null -> Error TopLevelMustHaveKeyCalledCases
46
+ | json -> Ok json
47
+
48
+ let parse_json_text (text: string): (case list, error) Result.t =
49
+ let open Result.Monad_infix in
50
+ parse_cases text >>=
51
+ to_list_note ExpectingListOfCases >>=
52
+ (sequence >> (List.map ~f:parse_case))
53
+
54
+ let show_error = function
55
+ | TopLevelMustHaveKeyCalledCases -> "Cannot parse this json - " ^
56
+ "expecting an object with a key: 'cases'"
57
+ | ExpectingMapForCase -> "Expected a json map for a test case"
58
+ | ExpectingListOfCases -> "Expected a top level map with key cases, " ^
59
+ "and a list of cases as its value."
60
+ | BadDescription -> "Case is missing a description or it is not a string."
61
+ | BadExpected -> "Case is missing an expected key or it is not a string."
@@ -0,0 +1,9 @@
1
+ open Core.Std
2
+ open Model
3
+
4
+ type error = TopLevelMustHaveKeyCalledCases | ExpectingListOfCases |
5
+ ExpectingMapForCase | BadDescription | BadExpected
6
+
7
+ val parse_json_text : string -> (case list, error) Result.t
8
+
9
+ val show_error : error -> string
@@ -0,0 +1,12 @@
1
+ open Core.Std
2
+
3
+ open Model
4
+
5
+ let optional_int ~(none: int) = function
6
+ | Int n when n = none -> "None"
7
+ | Int n -> "(Some " ^ Int.to_string n ^ ")"
8
+ | _ -> failwith "can't handle non-int parameter"
9
+
10
+ let fixup ~(stringify: parameter -> string) ~(slug: string) ~(key: string) ~(value: parameter) = match (slug, key) with
11
+ | ("hamming", "expected") -> optional_int (-1) value
12
+ | _ -> stringify value
@@ -0,0 +1,7 @@
1
+ open Core.Std
2
+
3
+ open Model
4
+
5
+ val optional_int : none: int -> parameter -> string
6
+
7
+ val fixup : stringify:(parameter -> string) -> slug:string -> key:string -> value:parameter -> string
@@ -0,0 +1,25 @@
1
+ open Core.Std
2
+
3
+ let is_directory =
4
+ Command.Spec.Arg_type.create
5
+ (fun n ->
6
+ match Sys.is_directory n with
7
+ | `Yes -> n
8
+ | `No | `Unknown ->
9
+ eprintf "'%s' is not a regular folder.\n%!" n;
10
+ exit 1
11
+ )
12
+
13
+ let command =
14
+ Command.basic
15
+ ~summary:"Generates test code from canonical data."
16
+ Command.Spec.(
17
+ empty
18
+ +> flag "-t" (optional_with_default "./templates" is_directory) ~doc:"string Directory containing templates."
19
+ +> flag "-c" (optional_with_default "../../../x-common/exercises" is_directory) ~doc:"string Directory containing canonical data."
20
+ +> flag "-o" (optional_with_default "../../exercises" is_directory) ~doc:"string Directory to output generated tests."
21
+ )
22
+ (fun templates_folder canonical_data_folder output_folder () -> Test_generator.run templates_folder canonical_data_folder output_folder)
23
+
24
+ let () =
25
+ Command.run ~version:"0.1" command
@@ -0,0 +1,62 @@
1
+ open Core.Std
2
+ open Parser
3
+ open Model
4
+ open Utils
5
+ open Codegen
6
+ open Special_cases
7
+
8
+ let find_template ~(template_text: string): (int * int * string) option =
9
+ let open Option.Monad_infix in
10
+ let str_contains pattern s = String.substr_index s ~pattern |> Option.is_some in
11
+ let lines = String.split_lines template_text |> List.to_array in
12
+ let start_index = find_arrayi lines ~f:(str_contains "(* GENERATED-CODE") |> Option.map ~f:fst in
13
+ let finish_index = (start_index >>= (fun start -> find_arrayi ~start lines ~f:(str_contains "END GENERATED-CODE *"))) |> Option.map ~f:fst in
14
+ let template_lines = Option.map2 start_index finish_index (fun s -> Array.slice lines (s+1)) in
15
+ Option.map2 start_index template_lines ~f:(fun s l -> (s, s + 1 + Array.length l, String.concat_array l ~sep:"\n"))
16
+
17
+ let splice_in_filled_in_code (start: int) (finish: int) ~(template: string) (substs: string list): string =
18
+ let lines = String.split_lines template |> List.to_array in
19
+ let before = Array.slice lines 0 start in
20
+ let subst = Array.of_list substs in
21
+ let after = Array.slice lines (finish + 1) (Array.length lines) in
22
+ let join = String.concat_array ~sep:"\n" in
23
+ String.concat [join before; join subst; join after] ~sep:"\n"
24
+
25
+ type content = string
26
+
27
+ let find_nested_files (name: string) (base: string): (string * content) list =
28
+ Sys.ls_dir base
29
+ |> List.filter ~f:(fun slug -> Sys.is_directory_exn (base ^ "/" ^ slug))
30
+ |> List.filter ~f:(fun slug -> Sys.file_exists_exn (base ^ "/" ^ slug ^ "/" ^ name))
31
+ |> List.map ~f:(fun slug -> (slug, In_channel.read_all (base ^ "/" ^ slug ^ "/" ^ name)))
32
+
33
+ let find_templates = find_nested_files "template.ml"
34
+
35
+ let find_canonical_data_files = find_nested_files "canonical-data.json"
36
+
37
+ let combine_files (templates: (string * content) list) (canonical_data: (string * content) list): (string * content * content) list =
38
+ List.filter_map templates ~f:(fun (n,t) -> (List.Assoc.find canonical_data ~equal:String.equal n |> Option.map ~f:(fun c -> (n,t,c))))
39
+
40
+ let generate_code ~slug ~template_file ~canonical_data_file =
41
+ let template = find_template template_file in
42
+ let template = Result.of_option template "cannot find a template" in
43
+ let cases = parse_json_text canonical_data_file in
44
+ let cases = Result.map_error cases show_error in
45
+ let open Result.Monad_infix in
46
+ template >>= fun (s,e,template) ->
47
+ cases >>= fun cs ->
48
+ let Ok substs = generate_code (fixup ~stringify:parameter_to_string ~slug) template cs in
49
+ Result.return (splice_in_filled_in_code s e ~template:template_file substs)
50
+
51
+ let output_tests (files: (string * content * content) list) (output_folder: string): unit =
52
+ let output_filepath name = output_folder ^ "/" ^ name ^ "/test.ml" in
53
+ let output1 (slug,t,c) =
54
+ let Ok code = generate_code slug t c in
55
+ Out_channel.write_all (output_filepath slug) code in
56
+ List.iter files ~f:output1
57
+
58
+ let run ~(templates_folder: string) ~(canonical_data_folder: string) ~(output_folder: string) =
59
+ let templates = find_templates templates_folder in
60
+ let canonical_data_files = find_canonical_data_files canonical_data_folder in
61
+ let combined = combine_files templates canonical_data_files in
62
+ output_tests combined output_folder
@@ -0,0 +1,6 @@
1
+ open Core.Std
2
+
3
+ (* finds a template within a file, returning the line numbers of the comment starting and ending the template, and the body of the template *)
4
+ val find_template : template_text: string -> (int * int * string) option
5
+
6
+ val run : templates_folder: string -> canonical_data_folder: string -> output_folder: string -> unit
@@ -0,0 +1,32 @@
1
+ open Core.Std
2
+ open Yojson.Safe
3
+ open Yojson.Safe.Util
4
+
5
+ let map2 (f: 'a -> 'b -> 'c) (r1: ('a, 'e) Result.t) (r2: ('b, 'e) Result.t): ('c, 'e) Result.t = match (r1, r2) with
6
+ | (Error x, _) -> Error x
7
+ | (_, Error x) -> Error x
8
+ | (Ok a, Ok b) -> Ok (f a b)
9
+
10
+ let sequence (rs: (('a, 'e) Result.t) list): (('a list), 'e) Result.t =
11
+ List.fold_right rs ~init:(Ok []) ~f:(map2 (fun x xs -> x :: xs))
12
+
13
+ let to_list_option json =
14
+ try Some (to_list json) with Type_error _ -> None
15
+
16
+ let to_list_note error json =
17
+ try Ok (to_list json) with Type_error _ -> Error error
18
+
19
+ let to_string_note error json =
20
+ try Ok (to_string json) with Type_error _ -> Error error
21
+
22
+ let safe_to_int_option json =
23
+ try Some (to_int json) with Type_error _ -> None
24
+
25
+ let (>>) f g = Fn.compose f g
26
+
27
+ let find_arrayi ?start:(start = 0) xs ~f =
28
+ let rec go i =
29
+ if i >= Array.length xs then None
30
+ else if f xs.(i) then Some (i, xs.(i))
31
+ else go (i + 1) in
32
+ go start
@@ -0,0 +1,18 @@
1
+ open Core.Std
2
+ open Yojson.Safe
3
+
4
+ val map2 : ('a -> 'b -> 'c) -> ('a, 'e) Result.t -> ('b, 'e) Result.t -> ('c, 'e) Result.t
5
+
6
+ val sequence : (('a, 'e) Result.t) list -> (('a list), 'e) Result.t
7
+
8
+ val to_list_option : json -> json list option
9
+
10
+ val to_list_note : 'e -> json -> ((json list, 'e) Result.t)
11
+
12
+ val to_string_note : 'e -> json -> ((string, 'e) Result.t)
13
+
14
+ val safe_to_int_option : json -> int option
15
+
16
+ val find_arrayi : ?start:int -> 'a array -> f:('a -> bool) -> (int * 'a) option
17
+
18
+ val (>>) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b