trackler 2.0.8.15 → 2.0.8.16

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.
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