trackler 2.0.8.15 → 2.0.8.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/clock/canonical-data.json +473 -425
  3. data/common/exercises/crypto-square/canonical-data.json +105 -95
  4. data/common/exercises/difference-of-squares/canonical-data.json +76 -62
  5. data/common/exercises/etl/canonical-data.json +67 -59
  6. data/common/exercises/meetup/canonical-data.json +859 -762
  7. data/common/exercises/meetup/description.md +13 -7
  8. data/common/exercises/minesweeper/canonical-data.json +21 -5
  9. data/common/exercises/nth-prime/canonical-data.json +23 -16
  10. data/common/exercises/nucleotide-count/canonical-data.json +49 -41
  11. data/common/exercises/ocr-numbers/canonical-data.json +204 -183
  12. data/common/exercises/pascals-triangle/canonical-data.json +38 -27
  13. data/common/exercises/queen-attack/canonical-data.json +125 -109
  14. data/common/exercises/rotational-cipher/canonical-data.json +1 -1
  15. data/common/exercises/triangle/canonical-data.json +103 -74
  16. data/lib/trackler/version.rb +1 -1
  17. data/tracks/csharp/docs/TESTS.md +7 -1
  18. data/tracks/csharp/exercises/{exercises.sln → Exercises.All.sln} +0 -0
  19. data/tracks/csharp/exercises/Exercises.Default.sln +1433 -0
  20. data/tracks/csharp/exercises/Exercises.Refactoring.sln +61 -0
  21. data/tracks/csharp/exercises/acronym/AcronymTest.cs +35 -11
  22. data/tracks/csharp/exercises/parallel-letter-frequency/ParallelLetterFrequencyTest.cs +2 -2
  23. data/tracks/delphi/docs/TESTS.md +2 -2
  24. data/tracks/elixir/exercises/bowling/bowling.exs +1 -1
  25. data/tracks/fsharp/docs/LEARNING.md +2 -1
  26. data/tracks/go/config.json +7 -1
  27. data/tracks/go/exercises/prime-factors/{primefactors_test.go → prime_factors_test.go} +4 -1
  28. data/tracks/go/exercises/protein-translation/protein_translation_test.go +6 -6
  29. data/tracks/go/exercises/pythagorean-triplet/example.go +2 -0
  30. data/tracks/go/exercises/pythagorean-triplet/pythagorean_triplet_test.go +8 -0
  31. data/tracks/julia/README.md +2 -0
  32. data/tracks/julia/config.json +9 -0
  33. data/tracks/julia/exercises/rotational-cipher/HINTS.md +21 -0
  34. data/tracks/julia/exercises/rotational-cipher/example.jl +16 -0
  35. data/tracks/julia/exercises/rotational-cipher/rotational-cipher.jl +0 -0
  36. data/tracks/julia/exercises/rotational-cipher/runtests.jl +51 -0
  37. data/tracks/ocaml/config.json +5 -0
  38. data/tracks/ocaml/exercises/connect/.merlin +3 -0
  39. data/tracks/ocaml/exercises/connect/Makefile +15 -0
  40. data/tracks/ocaml/exercises/connect/connect.mli +4 -0
  41. data/tracks/ocaml/exercises/connect/example.ml +80 -0
  42. data/tracks/ocaml/exercises/connect/test.ml +121 -0
  43. data/tracks/ocaml/tools/test-generator/templates/connect/template.ml +23 -0
  44. data/tracks/python/exercises/all-your-base/all_your_base_test.py +2 -0
  45. data/tracks/python/exercises/luhn/example.py +5 -8
  46. data/tracks/python/exercises/luhn/luhn_test.py +34 -24
  47. data/tracks/ruby/README.md +138 -23
  48. metadata +16 -4
@@ -0,0 +1,121 @@
1
+ open Core.Std
2
+ open OUnit2
3
+ open Connect
4
+
5
+ let show_player = function
6
+ | Some X -> "X"
7
+ | Some O -> "O"
8
+ | None -> "None"
9
+
10
+ let ae exp got = assert_equal ~printer:show_player exp got
11
+
12
+ let tests = [
13
+ "an empty board has no winner" >::(fun _ctxt ->
14
+ let board = [
15
+ ". . . . .";
16
+ " . . . . .";
17
+ " . . . . .";
18
+ " . . . . .";
19
+ " . . . . ."
20
+ ]
21
+ in
22
+ ae None (connect board)
23
+ );
24
+ "X can win on a 1x1 board" >::(fun _ctxt ->
25
+ let board = [
26
+ "X"
27
+ ]
28
+ in
29
+ ae (Some X) (connect board)
30
+ );
31
+ "O can win on a 1x1 board" >::(fun _ctxt ->
32
+ let board = [
33
+ "O"
34
+ ]
35
+ in
36
+ ae (Some O) (connect board)
37
+ );
38
+ "only edges does not make a winner" >::(fun _ctxt ->
39
+ let board = [
40
+ "O O O X";
41
+ " X . . X";
42
+ " X . . X";
43
+ " X O O O"
44
+ ]
45
+ in
46
+ ae None (connect board)
47
+ );
48
+ "illegal diagonal does not make a winner" >::(fun _ctxt ->
49
+ let board = [
50
+ "X O . .";
51
+ " O X X X";
52
+ " O X O .";
53
+ " . O X .";
54
+ " X X O O"
55
+ ]
56
+ in
57
+ ae None (connect board)
58
+ );
59
+ "nobody wins crossing adjacent angles" >::(fun _ctxt ->
60
+ let board = [
61
+ "X . . .";
62
+ " . X O .";
63
+ " O . X O";
64
+ " . O . X";
65
+ " . . O ."
66
+ ]
67
+ in
68
+ ae None (connect board)
69
+ );
70
+ "X wins crossing from left to right" >::(fun _ctxt ->
71
+ let board = [
72
+ ". O . .";
73
+ " O X X X";
74
+ " O X O .";
75
+ " X X O X";
76
+ " . O X ."
77
+ ]
78
+ in
79
+ ae (Some X) (connect board)
80
+ );
81
+ "O wins crossing from top to bottom" >::(fun _ctxt ->
82
+ let board = [
83
+ ". O . .";
84
+ " O X X X";
85
+ " O O O .";
86
+ " X X O X";
87
+ " . O X ."
88
+ ]
89
+ in
90
+ ae (Some O) (connect board)
91
+ );
92
+ "X wins using a convoluted path" >::(fun _ctxt ->
93
+ let board = [
94
+ ". X X . .";
95
+ " X . X . X";
96
+ " . X . X .";
97
+ " . X X . .";
98
+ " O O O O O"
99
+ ]
100
+ in
101
+ ae (Some X) (connect board)
102
+ );
103
+ "X wins using a spiral path" >::(fun _ctxt ->
104
+ let board = [
105
+ "O X X X X X X X X";
106
+ " O X O O O O O O O";
107
+ " O X O X X X X X O";
108
+ " O X O X O O O X O";
109
+ " O X O X X X O X O";
110
+ " O X O O O X O X O";
111
+ " O X X X X X O X O";
112
+ " O O O O O O O X O";
113
+ " X X X X X X X X O"
114
+ ]
115
+ in
116
+ ae (Some X) (connect board)
117
+ );
118
+ ]
119
+
120
+ let () =
121
+ run_test_tt_main ("connect tests" >::: tests)
@@ -0,0 +1,23 @@
1
+ open Core.Std
2
+ open OUnit2
3
+ open Connect
4
+
5
+ let show_player = function
6
+ | Some X -> "X"
7
+ | Some O -> "O"
8
+ | None -> "None"
9
+
10
+ let ae exp got = assert_equal ~printer:show_player exp got
11
+
12
+ let tests = [
13
+ (* TEST
14
+ "$description" >::(fun _ctxt ->
15
+ let board = $board
16
+ in
17
+ ae $expected (connect board)
18
+ );
19
+ END TEST *)
20
+ ]
21
+
22
+ let () =
23
+ run_test_tt_main ("connect tests" >::: tests)
@@ -3,6 +3,8 @@ import unittest
3
3
  from all_your_base import rebase
4
4
 
5
5
 
6
+ # test cases adapted from `x-common//canonical-data.json` @ version: 1.0.0
7
+
6
8
  class AllYourBaseTests(unittest.TestCase):
7
9
 
8
10
  def test_single_bit_to_one_decimal(self):
@@ -1,11 +1,11 @@
1
1
  class Luhn(object):
2
- def __init__(self, number):
3
- self.number = number
2
+ def __init__(self, string):
3
+ self.string = string.replace(" ", "")
4
4
 
5
5
  def addends(self):
6
6
  def luhn_transform(n):
7
7
  return (2 * n - 9) if (n > 4) else (2 * n)
8
- old_digits = [int(d) for d in str(self.number)]
8
+ old_digits = [int(d) for d in str(self.string)]
9
9
  return [(luhn_transform(n) if (i % 2 == 0) else n)
10
10
  for i, n in enumerate(old_digits, start=len(old_digits) % 2)]
11
11
 
@@ -13,9 +13,6 @@ class Luhn(object):
13
13
  return sum(self.addends())
14
14
 
15
15
  def is_valid(self):
16
+ if len(self.string) <= 1 or not self.string.isdigit():
17
+ return False
16
18
  return self.checksum() % 10 == 0
17
-
18
- @staticmethod
19
- def create(n):
20
- diff = (10 - Luhn(n * 10).checksum()) % 10
21
- return 10 * n + diff
@@ -1,46 +1,56 @@
1
- from collections import Counter
1
+ # -*- coding: utf-8 -*-
2
+
2
3
  import unittest
3
4
 
4
5
  from luhn import Luhn
5
6
 
6
7
 
7
8
  class LuhnTests(unittest.TestCase):
8
- def test_addends(self):
9
- # uses a Counter to avoid specifying order of return value
10
- self.assertEqual(Counter([1, 4, 1, 4, 1]),
11
- Counter(Luhn(12121).addends()))
9
+ def test_single_digit_strings_can_not_be_valid(self):
10
+ self.assertFalse(Luhn("1").is_valid())
11
+
12
+ def test_a_single_zero_is_invalid(self):
13
+ self.assertFalse(Luhn("0").is_valid())
14
+
15
+ def test_a_simple_valid_SIN_that_remains_valid_if_reversed(self):
16
+ self.assertTrue(Luhn("059").is_valid())
17
+
18
+ def test_a_simple_valid_SIN_that_becomes_invalid_if_reversed(self):
19
+ self.assertTrue(Luhn("59").is_valid())
20
+
21
+ def test_a_valid_Canadian_SIN(self):
22
+ self.assertTrue(Luhn("055 444 285").is_valid())
12
23
 
13
- def test_addends_large(self):
14
- # uses a Counter to avoid specifying order of return value
15
- self.assertEqual(Counter([7, 6, 6, 1]),
16
- Counter(Luhn(8631).addends()))
24
+ def test_invalid_Canadian_SIN(self):
25
+ self.assertFalse(Luhn("055 444 286").is_valid())
17
26
 
18
- def test_checksum1(self):
19
- self.assertEqual(22, Luhn(4913).checksum())
27
+ def test_invalid_credit_card(self):
28
+ self.assertFalse(Luhn("8273 1232 7352 0569").is_valid())
20
29
 
21
- def test_ckecksum2(self):
22
- self.assertEqual(21, Luhn(201773).checksum())
30
+ def test_valid_strings_with_a_non_digit_included_become_invalid(self):
31
+ self.assertFalse(Luhn("055a 444 285").is_valid())
23
32
 
24
- def test_invalid_number(self):
25
- self.assertFalse(Luhn(738).is_valid())
33
+ def test_valid_strings_with_punctuation_included_become_invalid(self):
34
+ self.assertFalse(Luhn("055-444-285").is_valid())
26
35
 
27
- def test_valid_number(self):
28
- self.assertTrue(Luhn(8739567).is_valid())
36
+ def test_valid_strings_with_symbols_included_become_invalid(self):
37
+ self.assertFalse(Luhn("055£ 444$ 285").is_valid())
29
38
 
30
- def test_create_valid_number1(self):
31
- self.assertEqual(1230, Luhn.create(123))
39
+ def test_single_zero_with_space_is_invalid(self):
40
+ self.assertFalse(Luhn("0").is_valid())
32
41
 
33
- def test_create_valid_number2(self):
34
- self.assertEqual(8739567, Luhn.create(873956))
42
+ def test_more_than_a_single_zero_is_valid(self):
43
+ self.assertTrue(Luhn("0000 0").is_valid())
35
44
 
36
- def test_create_valid_number3(self):
37
- self.assertEqual(8372637564, Luhn.create(837263756))
45
+ def test_input_digit_9_is_correctly_converted_to_output_digit_9(self):
46
+ self.assertTrue(Luhn("091").is_valid())
38
47
 
39
48
  def test_is_valid_can_be_called_repeatedly(self):
49
+ # Additional track specific test case
40
50
  # This test was added, because we saw many implementations
41
51
  # in which the first call to is_valid() worked, but the
42
52
  # second call failed().
43
- number = Luhn(8739567)
53
+ number = Luhn("055 444 285")
44
54
  self.assertTrue(number.is_valid())
45
55
  self.assertTrue(number.is_valid())
46
56
 
@@ -65,11 +65,17 @@ Note that flags which have an attached value, like above, must take the form
65
65
  ### Generated Test Suites
66
66
 
67
67
  If you find an `example.tt` file in a problem directory, then the test suite is
68
- generated from shared data. In this case changing the test file itself will
69
- not be enough.
68
+ generated from shared data, which can be found in the exercise definition in the [x-common][]
69
+ repository.
70
70
 
71
- You will need to have cloned [the shared metadata](https://github.com/exercism/x-common)
72
- at the same level as the xruby repository. E.g.
71
+ Typically you will want to do one of the following:
72
+
73
+ * [Regenerate the test suite](#regenerating-an-exercise) based on updated canonical data
74
+ * [Make changes to a generated exercise](#changing-a-generated-exercise)
75
+ * [Implement a new generator](#implementing-a-generator)
76
+
77
+ Generated exercises depend on the [the shared metadata][x-common], which must be
78
+ cloned to the same directory that contains your clone of the xruby repository:
73
79
 
74
80
  ```
75
81
  tree -L 1 ~/code/exercism
@@ -77,38 +83,145 @@ tree -L 1 ~/code/exercism
77
83
  └── xruby
78
84
  ```
79
85
 
80
- 1. `xruby/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`.
81
- 1. `x-common/$PROBLEM.json` - the shared inputs and outputs for the problem.
82
- 1. `lib/$PROBLEM.rb` - the logic for turning the data into tests.
83
- 1. `xruby/bin/generate $PROBLEM` - the command to actually generate the test suite.
84
- 1. `.version` - used to keep track of the version of the test files as the data changes.
86
+ #### Regenerating an Exercise
87
+
88
+ From within the xruby directory, run the following command, where $PROBLEM is the slug
89
+ of the exercise, e.g. `clock` or `atbash-cipher`:
90
+
91
+ ```
92
+ bin/generate $PROBLEM
93
+ ```
94
+
95
+ #### Changing a Generated Exercise
96
+
97
+ The `$PROBLEM/$PROBLEM_test.rb` will never be edited directly.
98
+
99
+ There are two reasons why a test suite might change:
100
+
101
+ 1. the tests are wrong (an incorrect expectation, a missing edge case, etc)
102
+ 1. there might be issues with the style or boilerplate
103
+
104
+ In the first case, the changes need to be made to the `canonical-data.json` file for
105
+ the exercise, which lives in the x-common repository.
106
+
107
+ ```
108
+ ../x-common/exercises/$PROBLEM/
109
+ ├── canonical-data.json
110
+ ├── description.md
111
+ └── metadata.yml
112
+ ```
113
+
114
+ This change will need to be submitted as a pull request to the x-common repository. This pull
115
+ request needs to be merged before you can regenerate the exercise.
85
116
 
86
- Additionally, there is some common generator logic in `lib/generator.rb`.
117
+ Changes that don't have to do directly with the test inputs and outputs, will either need to be
118
+ made to `exercises/$PROBLEM/example.tt` or `lib/$PROBLEM_cases.rb`. Then you can regenerate the
119
+ exercise with `bin/generate $PROBLEM`.
87
120
 
88
- For example, take a look at the `hamming.json` file in the x-common repository, as well
89
- as the following files in the xruby repository:
121
+ #### Implementing a Generator
90
122
 
91
- 1. `hamming/example.tt`
92
- 1. `bin/generate hamming`
93
- 1. `lib/hamming.rb`
94
- 1. `lib/generator.rb`
123
+ You will need to implement three files to create a generator:
95
124
 
96
- The `hamming/hamming_test.rb` will never be edited directly. If there's a missing test case,
97
- then additional inputs/outputs should be submitted to the x-common repository.
125
+ 1. `exercises/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`.
126
+ 1. `exercises/$PROBLEM/.meta/.version` - used to keep track of the version of the test files as the data changes.
127
+ 1. `lib/$PROBLEM_cases.rb` - the logic for turning the data into tests.
98
128
 
99
- Changes to the test suite (style, boilerplate, etc) will probably have to be made to
100
- `example.tt`.
129
+ You will not need to touch the top-level script, `bin/generate`.
101
130
 
102
- ### Exercise Generators
131
+ The `bin/generate` command relies on some common logic implemented in `lib/generator.rb`.
132
+ You probably won't need to touch that, either.
103
133
 
104
- If you wish to create a new generator, or edit an existing one, the generators currently live in the lib directory and are named `$PROBLEM_cases.rb`. For example, the hamming generator is `lib/hamming_cases.rb`.
134
+ The `lib/$PROBLEM_cases.rb` file should contain a small class that wraps the JSON for a single test case:
105
135
 
106
- All generators currently adhere to a common public interface, and must define the following three methods:
136
+ ```
137
+ require 'exercise_cases'
138
+
139
+ class ProblemNameCase < OpenStruct
140
+ def test_name
141
+ 'test_%s' % description.gsub(/[ -]/, '_')
142
+ end
143
+
144
+ def workload
145
+ # implement main logic of test here
146
+ end
147
+
148
+ def skipped
149
+ index.zero? ? '# skip' : 'skip'
150
+ end
151
+ end
152
+ ```
153
+
154
+ Instead of `ProblemName` use the name of the actual problem. This is important, since
155
+ the generator script will infer the name of the class from the argument that is passed.
156
+
157
+ This class must implement the following methods:
107
158
 
108
159
  - `test_name` - Returns the name of the test (i.e `test_one_equals_one`)
109
160
  - `workload` - Returns the main syntax for the test. This will vary depending on the test generator and its underlying implementation
110
161
  - `skipped` - Returns skip syntax (i.e. `skip` or `# skip`)
111
162
 
163
+ Beyond that, you can implement any helper methods that you need.
164
+
165
+ Below this class, implement a small loop that will generate all the test cases by reading the
166
+ `canonical-data.json` file, and looping through the test cases.
167
+
168
+ You will need to adjust the logic to match the structure of the canonical data.
169
+
170
+ For example, if there is a single top-level key named "cases", then you can loop through
171
+ them as follows:
172
+
173
+ ```
174
+ ProblemNameCases = proc do |data|
175
+ JSON.parse(data)['cases'].map.with_index do |row, i|
176
+ ProblemNameCase.new(row.merge('index' => i))
177
+ end
178
+ end
179
+ ```
180
+
181
+ If there are multiple sections, then you will need to loop through the sections, and then
182
+ loop through each of the cases in an inner loop:
183
+
184
+ ```
185
+ ProblemNameCases = proc do |data|
186
+ i = 0
187
+ json = JSON.parse(data)
188
+ cases = []
189
+ %w(section1 section2 etc).each do |section|
190
+ json[section]['cases'].each do |row|
191
+ row = row.merge(row.merge('index' => i, 'section' => section))
192
+ cases << ProblemNameCase.new(row)
193
+ i += 1
194
+ end
195
+ end
196
+ cases
197
+ end
198
+ ```
199
+
200
+ Finally, you need to create a text template, `example.tt`, as the bases for the test suite.
201
+
202
+ Start with the following boilerplate, and adjust as necessary:
203
+
204
+ ```
205
+ #!/usr/bin/env ruby
206
+ gem 'minitest', '>= 5.0.0'
207
+ require 'minitest/autorun'
208
+ require_relative '$PROBLEM'
209
+
210
+ # Common test data version: <%= abbreviated_commit_hash %>
211
+ class ProblemNameTest < Minitest::Test<% test_cases.each do |test_case| %>
212
+ def <%= test_case.name %>
213
+ <%= test_case.skipped %>
214
+ assert_equal <%= test_case.expected %>, <%= test_case.work_load %>
215
+ end
216
+ <% end %>
217
+ <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
218
+ def test_bookkeeping
219
+ skip
220
+ assert_equal <%= version %>, BookKeeping::VERSION
221
+ end
222
+ end
223
+ ```
224
+
112
225
  ## Pull Requests
113
226
 
114
227
  We welcome pull requests that provide fixes to existing test suites (missing
@@ -168,3 +281,5 @@ Copyright (c) 2014 Katrina Owen, _@kytrinyx.com
168
281
 
169
282
  ## Ruby icon
170
283
  The Ruby icon is the Vienna.rb logo, and is used with permission. Thanks Floor Dress :)
284
+
285
+ [x-common]: https://github.com/exercism/x-common