trackler 1.0.1.0 → 1.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/bin/bump-content +33 -0
- data/common/exercises/bowling/canonical-data.json +78 -77
- data/common/exercises/counter/.deprecated +1 -0
- data/common/exercises/point-mutations/.deprecated +1 -0
- data/common/exercises/say/canonical-data.json +83 -0
- data/common/exercises/word-count/canonical-data.json +25 -5
- data/lib/trackler/version.rb +1 -1
- data/tracks/c/config.json +9 -0
- data/tracks/c/exercises/largest-series-product/makefile +16 -0
- data/tracks/c/exercises/largest-series-product/src/example.c +54 -0
- data/tracks/c/exercises/largest-series-product/src/example.h +9 -0
- data/tracks/c/exercises/largest-series-product/test/test_largest_series_product.c +114 -0
- data/tracks/c/exercises/largest-series-product/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/largest-series-product/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/largest-series-product/test/vendor/unity_internals.h +701 -0
- data/tracks/clojure/_test/check_exercises.clj +7 -6
- data/tracks/clojure/config.json +268 -53
- data/tracks/clojure/exercises/flatten-array/src/example.clj +16 -0
- data/tracks/clojure/exercises/flatten-array/test/flatten_array_test.clj +28 -0
- data/tracks/clojure/exercises/perfect-numbers/project.clj +4 -0
- data/tracks/clojure/exercises/perfect-numbers/src/example.clj +17 -0
- data/tracks/clojure/exercises/perfect-numbers/test/perfect_numbers_test.clj +20 -0
- data/tracks/ecmascript/exercises/grade-school/grade-school.spec.js +7 -0
- data/tracks/elixir/.travis.yml +3 -0
- data/tracks/elixir/bin/dialyzer_check.sh +28 -0
- data/tracks/elixir/config.json +13 -1
- data/tracks/elixir/docs/TESTS.md +81 -0
- data/tracks/elixir/exercises/bank-account/example.exs +1 -1
- data/tracks/elixir/exercises/binary-search/binary_search_test.exs +5 -0
- data/tracks/elixir/exercises/clock/clock.exs +23 -0
- data/tracks/elixir/exercises/clock/clock_test.exs +281 -0
- data/tracks/elixir/exercises/clock/example.exs +55 -0
- data/tracks/elixir/exercises/prime-factors/example.exs +1 -2
- data/tracks/elixir/exercises/robot-simulator/example.exs +2 -3
- data/tracks/elixir/mix.exs +2 -1
- data/tracks/go/docs/TESTS.md +1 -1
- data/tracks/go/exercises/gigasecond/gigasecond_test.go +0 -2
- data/tracks/go/exercises/palindrome-products/palindrome_products_test.go +38 -22
- data/tracks/haskell/.travis.yml +26 -7
- data/tracks/haskell/config.json +0 -69
- data/tracks/haskell/exercises/anagram/examples/list-string/Anagram.hs +10 -0
- data/tracks/haskell/exercises/anagram/examples/list-string/package.yaml +17 -0
- data/tracks/haskell/exercises/anagram/{src/Example.hs → examples/set-text/Anagram.hs} +0 -0
- data/tracks/haskell/exercises/anagram/examples/set-text/package.yaml +20 -0
- data/tracks/haskell/exercises/anagram/package.yaml +0 -3
- data/tracks/idris/config.json +3 -3
- data/tracks/kotlin/config.json +207 -43
- data/tracks/lfe/config.json +152 -32
- data/tracks/lfe/docs/TESTS.md +18 -56
- data/tracks/lua/docs/ABOUT.md +9 -0
- data/tracks/mips/config.json +72 -16
- data/tracks/ocaml/config.json +6 -0
- data/tracks/ocaml/exercises/etl/.merlin +5 -0
- data/tracks/ocaml/exercises/etl/Makefile +11 -0
- data/tracks/ocaml/exercises/etl/etl.mli +2 -0
- data/tracks/ocaml/exercises/etl/example.ml +7 -0
- data/tracks/ocaml/exercises/etl/test.ml +35 -0
- data/tracks/ocaml/exercises/raindrops/test.ml +1 -1
- data/tracks/php/config.json +7 -1
- data/tracks/php/exercises/acronym/acronym_test.php +56 -0
- data/tracks/php/exercises/acronym/example.php +20 -0
- data/tracks/racket/config.json +109 -22
- data/tracks/ruby/README.md +3 -3
- data/tracks/ruby/bin/generate +16 -0
- data/tracks/ruby/exercises/alphametics/.version +1 -1
- data/tracks/ruby/exercises/alphametics/alphametics_test.rb +24 -22
- data/tracks/ruby/exercises/alphametics/example.rb +1 -1
- data/tracks/ruby/lib/bracket_push_cases.rb +3 -3
- data/tracks/ruby/lib/{raindrop_cases.rb → raindrops_cases.rb} +1 -1
- data/tracks/rust/config.json +1 -0
- data/tracks/rust/exercises/atbash-cipher/Cargo.lock +4 -0
- data/tracks/rust/exercises/atbash-cipher/Cargo.toml +3 -0
- data/tracks/rust/exercises/atbash-cipher/example.rs +36 -0
- data/tracks/rust/exercises/atbash-cipher/tests/atbash-cipher.rs +82 -0
- data/tracks/rust/problems.md +1 -0
- data/tracks/scala/config.json +8 -0
- data/tracks/scala/exercises/sum-of-multiples/build.sbt +3 -0
- data/tracks/scala/exercises/sum-of-multiples/example.scala +10 -0
- data/tracks/scala/exercises/sum-of-multiples/src/main/scala/.keep +0 -0
- data/tracks/scala/exercises/sum-of-multiples/src/test/scala/SumOfMultiplesTest.scala +62 -0
- metadata +43 -23
- data/tracks/ruby/bin/generate-acronym +0 -7
- data/tracks/ruby/bin/generate-alphametics +0 -8
- data/tracks/ruby/bin/generate-binary +0 -7
- data/tracks/ruby/bin/generate-bracket-push +0 -7
- data/tracks/ruby/bin/generate-clock +0 -7
- data/tracks/ruby/bin/generate-connect +0 -7
- data/tracks/ruby/bin/generate-custom-set +0 -7
- data/tracks/ruby/bin/generate-difference-of-squares +0 -7
- data/tracks/ruby/bin/generate-gigasecond +0 -7
- data/tracks/ruby/bin/generate-hamming +0 -7
- data/tracks/ruby/bin/generate-hello-world +0 -7
- data/tracks/ruby/bin/generate-largest-series-product +0 -7
- data/tracks/ruby/bin/generate-leap +0 -7
- data/tracks/ruby/bin/generate-nth-prime +0 -7
- data/tracks/ruby/bin/generate-pangram +0 -7
- data/tracks/ruby/bin/generate-raindrops +0 -7
- data/tracks/ruby/bin/generate-rna-transcription +0 -7
- data/tracks/ruby/bin/generate-roman-numerals +0 -7
- data/tracks/ruby/bin/generate-run-length-encoding +0 -7
- data/tracks/ruby/bin/generate-two-bucket +0 -7
@@ -0,0 +1,281 @@
|
|
1
|
+
if !System.get_env("EXERCISM_TEST_EXAMPLES") do
|
2
|
+
Code.load_file("clock.exs", __DIR__)
|
3
|
+
end
|
4
|
+
|
5
|
+
ExUnit.start
|
6
|
+
ExUnit.configure exclude: :pending, trace: true
|
7
|
+
|
8
|
+
defmodule ClockTest do
|
9
|
+
use ExUnit.Case
|
10
|
+
|
11
|
+
#@tag :pending
|
12
|
+
test "to_string" do
|
13
|
+
try do
|
14
|
+
to_string(%Clock{})
|
15
|
+
rescue
|
16
|
+
Protocol.UndefinedError ->
|
17
|
+
refute(true, """
|
18
|
+
Can't convert Clock to string.
|
19
|
+
Hint: implement the String.Chars protocol for Clock.
|
20
|
+
http://elixir-lang.org/getting-started/protocols.html
|
21
|
+
http://elixir-lang.org/docs/stable/elixir/String.Chars.html
|
22
|
+
""")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "create" do
|
27
|
+
@tag :pending
|
28
|
+
test "on the hour" do
|
29
|
+
assert Clock.new(8, 0) |> to_string == "08:00"
|
30
|
+
end
|
31
|
+
|
32
|
+
@tag :pending
|
33
|
+
test "past the hour" do
|
34
|
+
assert Clock.new(11, 9) |> to_string == "11:09"
|
35
|
+
end
|
36
|
+
|
37
|
+
@tag :pending
|
38
|
+
test "midnight is zero hours" do
|
39
|
+
assert Clock.new(24, 0) |> to_string == "00:00"
|
40
|
+
end
|
41
|
+
|
42
|
+
@tag :pending
|
43
|
+
test "hour rolls over" do
|
44
|
+
assert Clock.new(25, 0) |> to_string == "01:00"
|
45
|
+
end
|
46
|
+
|
47
|
+
@tag :pending
|
48
|
+
test "hour rolls over continuously" do
|
49
|
+
assert Clock.new(100, 0) |> to_string == "04:00"
|
50
|
+
end
|
51
|
+
|
52
|
+
@tag :pending
|
53
|
+
test "sixty minutes is next hour" do
|
54
|
+
assert Clock.new(1, 60) |> to_string == "02:00"
|
55
|
+
end
|
56
|
+
|
57
|
+
@tag :pending
|
58
|
+
test "minutes roll over" do
|
59
|
+
assert Clock.new(0, 160) |> to_string == "02:40"
|
60
|
+
end
|
61
|
+
|
62
|
+
@tag :pending
|
63
|
+
test "minutes roll over continuously" do
|
64
|
+
assert Clock.new(0, 1723) |> to_string == "04:43"
|
65
|
+
end
|
66
|
+
|
67
|
+
@tag :pending
|
68
|
+
test "hour and minutes roll over" do
|
69
|
+
assert Clock.new(25, 160) |> to_string == "03:40"
|
70
|
+
end
|
71
|
+
|
72
|
+
@tag :pending
|
73
|
+
test "hour and minutes roll over continuously" do
|
74
|
+
assert Clock.new(201, 3001) |> to_string == "11:01"
|
75
|
+
end
|
76
|
+
|
77
|
+
@tag :pending
|
78
|
+
test "hour and minutes roll over to exactly midnight" do
|
79
|
+
assert Clock.new(72, 8640) |> to_string == "00:00"
|
80
|
+
end
|
81
|
+
|
82
|
+
@tag :pending
|
83
|
+
test "negative hour" do
|
84
|
+
assert Clock.new(-1, 15) |> to_string == "23:15"
|
85
|
+
end
|
86
|
+
|
87
|
+
@tag :pending
|
88
|
+
test "negative hour rolls over" do
|
89
|
+
assert Clock.new(-25, 0) |> to_string == "23:00"
|
90
|
+
end
|
91
|
+
|
92
|
+
@tag :pending
|
93
|
+
test "negative hour rolls over continuously" do
|
94
|
+
assert Clock.new(-91, 0) |> to_string == "05:00"
|
95
|
+
end
|
96
|
+
|
97
|
+
@tag :pending
|
98
|
+
test "negative minutes" do
|
99
|
+
assert Clock.new(1, -40) |> to_string == "00:20"
|
100
|
+
end
|
101
|
+
|
102
|
+
@tag :pending
|
103
|
+
test "negative minutes roll over" do
|
104
|
+
assert Clock.new(1, -160) |> to_string == "22:20"
|
105
|
+
end
|
106
|
+
|
107
|
+
@tag :pending
|
108
|
+
test "negative minutes roll over continuously" do
|
109
|
+
assert Clock.new(1, -4820) |> to_string == "16:40"
|
110
|
+
end
|
111
|
+
|
112
|
+
@tag :pending
|
113
|
+
test "negative hour and minutes roll over" do
|
114
|
+
assert Clock.new(-25, -160) |> to_string == "20:20"
|
115
|
+
end
|
116
|
+
|
117
|
+
@tag :pending
|
118
|
+
test "negative hour and minutes roll over continuously" do
|
119
|
+
assert Clock.new(-121, -5810) |> to_string == "22:10"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "add" do
|
124
|
+
@tag :pending
|
125
|
+
test "add minutes" do
|
126
|
+
assert Clock.new(10, 0) |> Clock.add(3) |> to_string == "10:03"
|
127
|
+
end
|
128
|
+
|
129
|
+
@tag :pending
|
130
|
+
test "add no minutes" do
|
131
|
+
assert Clock.new(6, 41) |> Clock.add(0) |> to_string == "06:41"
|
132
|
+
end
|
133
|
+
|
134
|
+
@tag :pending
|
135
|
+
test "add to next hour" do
|
136
|
+
assert Clock.new(0, 45) |> Clock.add(40) |> to_string == "01:25"
|
137
|
+
end
|
138
|
+
|
139
|
+
@tag :pending
|
140
|
+
test "add more than one hour" do
|
141
|
+
assert Clock.new(10, 0) |> Clock.add(61) |> to_string == "11:01"
|
142
|
+
end
|
143
|
+
|
144
|
+
@tag :pending
|
145
|
+
test "add more than two hours with carry" do
|
146
|
+
assert Clock.new(0, 45) |> Clock.add(160) |> to_string == "03:25"
|
147
|
+
end
|
148
|
+
|
149
|
+
@tag :pending
|
150
|
+
test "add across midnight" do
|
151
|
+
assert Clock.new(23, 59) |> Clock.add(2) |> to_string == "00:01"
|
152
|
+
end
|
153
|
+
|
154
|
+
@tag :pending
|
155
|
+
test "add more than one day (1500 min = 25 hrs)" do
|
156
|
+
assert Clock.new(5, 32) |> Clock.add(1500) |> to_string == "06:32"
|
157
|
+
end
|
158
|
+
|
159
|
+
@tag :pending
|
160
|
+
test "add more than two days" do
|
161
|
+
assert Clock.new(1, 1) |> Clock.add(3500) |> to_string == "11:21"
|
162
|
+
end
|
163
|
+
|
164
|
+
@tag :pending
|
165
|
+
test "subtract minutes" do
|
166
|
+
assert Clock.new(10, 3) |> Clock.add(-3) |> to_string == "10:00"
|
167
|
+
end
|
168
|
+
|
169
|
+
@tag :pending
|
170
|
+
test "subtract to previous hour" do
|
171
|
+
assert Clock.new(10, 3) |> Clock.add(-30) |> to_string == "09:33"
|
172
|
+
end
|
173
|
+
|
174
|
+
@tag :pending
|
175
|
+
test "subtract more than an hour" do
|
176
|
+
assert Clock.new(10, 3) |> Clock.add(-70) |> to_string == "08:53"
|
177
|
+
end
|
178
|
+
|
179
|
+
@tag :pending
|
180
|
+
test "subtract across midnight" do
|
181
|
+
assert Clock.new(0, 3) |> Clock.add(-4) |> to_string == "23:59"
|
182
|
+
end
|
183
|
+
|
184
|
+
@tag :pending
|
185
|
+
test "subtract more than two hours" do
|
186
|
+
assert Clock.new(0, 0) |> Clock.add(-160) |> to_string == "21:20"
|
187
|
+
end
|
188
|
+
|
189
|
+
@tag :pending
|
190
|
+
test "subtract more than two hours with borrow" do
|
191
|
+
assert Clock.new(6, 15) |> Clock.add(-160) |> to_string == "03:35"
|
192
|
+
end
|
193
|
+
|
194
|
+
@tag :pending
|
195
|
+
test "subtract more than one day (1500 min = 25 hrs)" do
|
196
|
+
assert Clock.new(5, 32) |> Clock.add(-1500) |> to_string == "04:32"
|
197
|
+
end
|
198
|
+
|
199
|
+
@tag :pending
|
200
|
+
test "subtract more than two days" do
|
201
|
+
assert Clock.new(2, 20) |> Clock.add(-3000) |> to_string == "00:20"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "==" do
|
206
|
+
@tag :pending
|
207
|
+
test "clocks with same time" do
|
208
|
+
assert Clock.new(15, 37) == Clock.new(15, 37)
|
209
|
+
end
|
210
|
+
|
211
|
+
@tag :pending
|
212
|
+
test "clocks a minute apart" do
|
213
|
+
refute Clock.new(15, 36) == Clock.new(15, 37)
|
214
|
+
end
|
215
|
+
|
216
|
+
@tag :pending
|
217
|
+
test "clocks an hour apart" do
|
218
|
+
refute Clock.new(14, 37) == Clock.new(15, 37)
|
219
|
+
end
|
220
|
+
|
221
|
+
@tag :pending
|
222
|
+
test "clocks with hour overflow" do
|
223
|
+
assert Clock.new(10, 37) == Clock.new(34, 37)
|
224
|
+
end
|
225
|
+
|
226
|
+
@tag :pending
|
227
|
+
test "clocks with hour overflow by several days" do
|
228
|
+
assert Clock.new(3, 11) == Clock.new(99, 11)
|
229
|
+
end
|
230
|
+
|
231
|
+
@tag :pending
|
232
|
+
test "clocks with negative hour" do
|
233
|
+
assert Clock.new(22, 40) == Clock.new(-2, 40)
|
234
|
+
end
|
235
|
+
|
236
|
+
@tag :pending
|
237
|
+
test "clocks with negative hour that wraps" do
|
238
|
+
assert Clock.new(17, 3) == Clock.new(-31, 3)
|
239
|
+
end
|
240
|
+
|
241
|
+
@tag :pending
|
242
|
+
test "clocks with negative hour that wraps multiple times" do
|
243
|
+
assert Clock.new(13, 49) == Clock.new(-83, 49)
|
244
|
+
end
|
245
|
+
|
246
|
+
@tag :pending
|
247
|
+
test "clocks with minute overflow" do
|
248
|
+
assert Clock.new(0, 1) == Clock.new(0, 1441)
|
249
|
+
end
|
250
|
+
|
251
|
+
@tag :pending
|
252
|
+
test "clocks with minute overflow by several days" do
|
253
|
+
assert Clock.new(2, 2) == Clock.new(2, 4322)
|
254
|
+
end
|
255
|
+
|
256
|
+
@tag :pending
|
257
|
+
test "clocks with negative minute" do
|
258
|
+
assert Clock.new(2, 40) == Clock.new(3, -20)
|
259
|
+
end
|
260
|
+
|
261
|
+
@tag :pending
|
262
|
+
test "clocks with negative minute that wraps" do
|
263
|
+
assert Clock.new(4, 10) == Clock.new(5, -1490)
|
264
|
+
end
|
265
|
+
|
266
|
+
@tag :pending
|
267
|
+
test "clocks with negative minute that wraps multiple times" do
|
268
|
+
assert Clock.new(6, 15) == Clock.new(6, -4305)
|
269
|
+
end
|
270
|
+
|
271
|
+
@tag :pending
|
272
|
+
test "clocks with negative hours and minutes" do
|
273
|
+
assert Clock.new(7, 32) == Clock.new(-12, -268)
|
274
|
+
end
|
275
|
+
|
276
|
+
@tag :pending
|
277
|
+
test "clocks with negative hours and minutes that wrap" do
|
278
|
+
assert Clock.new(18, 7) == Clock.new(-54, -11513)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
defmodule Clock do
|
2
|
+
defstruct hour: 0, minute: 0
|
3
|
+
@type t :: %Clock{hour: integer, minute: integer}
|
4
|
+
@type t(hour, minute) :: %Clock{hour: hour, minute: minute}
|
5
|
+
|
6
|
+
@doc """
|
7
|
+
Returns a string representation of a clock:
|
8
|
+
|
9
|
+
iex> Clock.new(8, 9) |> to_string
|
10
|
+
"08:09"
|
11
|
+
"""
|
12
|
+
@spec new(integer, integer) :: Clock.t
|
13
|
+
def new(hour, minute) do
|
14
|
+
rollover(%Clock{hour: hour, minute: minute})
|
15
|
+
end
|
16
|
+
|
17
|
+
@doc """
|
18
|
+
Adds two clock times:
|
19
|
+
|
20
|
+
iex> Clock.new(10, 0) |> Clock.add(3) |> to_string
|
21
|
+
"10:03"
|
22
|
+
"""
|
23
|
+
@spec add(Clock.t, integer) :: Clock.t
|
24
|
+
def add(%Clock{hour: hour, minute: minute}, add_minute) do
|
25
|
+
new(hour, minute + add_minute)
|
26
|
+
end
|
27
|
+
|
28
|
+
defp rollover(%Clock{hour: hour, minute: minute}) do
|
29
|
+
{carry_hour, minute} = roll_minute(minute)
|
30
|
+
%Clock{hour: roll_hour(hour + carry_hour), minute: minute}
|
31
|
+
end
|
32
|
+
|
33
|
+
defp roll_hour(hour) when hour < 0 and rem(hour, 24) == 0, do: 0
|
34
|
+
defp roll_hour(hour) when hour < 0, do: 24 + rem(hour, 24)
|
35
|
+
defp roll_hour(hour) when hour >= 24, do: rem(hour, 24)
|
36
|
+
defp roll_hour(hour), do: hour
|
37
|
+
|
38
|
+
defp roll_minute(minute) when minute < 0 do
|
39
|
+
{div(minute, 60) - 1, 60 + rem(minute, 60)}
|
40
|
+
end
|
41
|
+
defp roll_minute(minute) when minute >= 60 do
|
42
|
+
{div(minute, 60), rem(minute, 60)}
|
43
|
+
end
|
44
|
+
defp roll_minute(minute), do: {0, minute}
|
45
|
+
|
46
|
+
defimpl String.Chars, for: Clock do
|
47
|
+
def to_string(%Clock{hour: hour, minute: minute}) do
|
48
|
+
"#{format(hour)}:#{format(minute)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
defp format(number) do
|
52
|
+
number |> Integer.to_string |> String.pad_leading(2, "0")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
defmodule PrimeFactors do
|
2
2
|
@spec factors_for(pos_integer) :: [pos_integer]
|
3
3
|
def factors_for(number) do
|
4
|
-
do_factors(number)
|
4
|
+
do_factors(number, 2, [])
|
5
5
|
end
|
6
6
|
|
7
|
-
defp do_factors(_, i \\ 2, acc \\ [])
|
8
7
|
defp do_factors(1, _, acc),
|
9
8
|
do: Enum.reverse(acc)
|
10
9
|
defp do_factors(n, i, acc) when n < i * i,
|
@@ -27,15 +27,14 @@ defmodule RobotSimulator do
|
|
27
27
|
def direction(%RobotSimulator{direction: dir}), do: dir
|
28
28
|
|
29
29
|
defp orient(%RobotSimulator{} = robot, direction) when direction in @valid_directions do
|
30
|
-
%
|
30
|
+
%{ robot | direction: direction }
|
31
31
|
end
|
32
32
|
defp orient({ :error, _ } = error, _), do: error
|
33
33
|
defp orient(_, _), do: { :error, "invalid direction" }
|
34
34
|
|
35
35
|
defp place(%RobotSimulator{} = robot, { x, y } = position) when is_integer(x) and is_integer(y) do
|
36
|
-
%
|
36
|
+
%{ robot | position: position }
|
37
37
|
end
|
38
|
-
defp place({ :error, _ } = error, _), do: error
|
39
38
|
defp place(_, _), do: { :error, "invalid position" }
|
40
39
|
|
41
40
|
defp move("R", %RobotSimulator{ direction: direction } = robot), do: robot |> orient(direction |> rotate_right)
|
data/tracks/elixir/mix.exs
CHANGED
data/tracks/go/docs/TESTS.md
CHANGED
@@ -38,7 +38,7 @@ Your first goal it to get something to compile, even though it fails tests. For
|
|
38
38
|
|
39
39
|
### Fixing
|
40
40
|
|
41
|
-
Tests will often stop at the first error. Fix that one, repeat until no errors. `go test` has useful options. `go test -v` will give more verbose output. `go test -run <regexp>` will run just tests with names that match
|
41
|
+
Tests will often stop at the first error. Fix that one, repeat until no errors. `go test` has useful options. `go test -v` will give more verbose output. `go test -run <regexp>` will run just tests with names that match `<regexp>`.
|
42
42
|
|
43
43
|
Panics produce lots of output. It might seem scary at first, but be brave. Look at the very top of the panic output for the panic message. That should give a general description of the problem. Then read through the rest of it looking for the first reference to your code. That will often point right to the problem.
|
44
44
|
|
@@ -9,20 +9,15 @@ import (
|
|
9
9
|
|
10
10
|
const targetTestVersion = 1
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
/* API to implement:
|
13
|
+
|
14
|
+
type Product struct {
|
15
|
+
Product int // palindromic, of course
|
16
|
+
Factorizations [][2]int //list of all possible two-factor factorizations of Product, within given limits, in order
|
17
|
+
}
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
// Product int // palindromic, of course
|
21
|
-
// // list of all possible two-factor factorizations of Product, within
|
22
|
-
// // given limits, in order
|
23
|
-
// Factorizations [][2]int
|
24
|
-
// }
|
25
|
-
// func Products(fmin, fmax int) (pmin, pmax Product, error)
|
19
|
+
func Products(fmin, fmax int) (pmin, pmax Product, error)
|
20
|
+
*/
|
26
21
|
|
27
22
|
var testData = []struct {
|
28
23
|
// input to Products(): range limits for factors of the palindrome
|
@@ -45,29 +40,44 @@ var testData = []struct {
|
|
45
40
|
""},
|
46
41
|
{4, 10, Product{}, Product{}, "No palindromes"},
|
47
42
|
{10, 4, Product{}, Product{}, "fmin > fmax"},
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
}
|
44
|
+
|
45
|
+
// Bonus curiosities. Can a negative number be a palindrome? Most say no.
|
46
|
+
var bonusData = []struct {
|
47
|
+
fmin, fmax int
|
48
|
+
pmin, pmax Product
|
49
|
+
errPrefix string
|
50
|
+
}{
|
51
|
+
// The following two test cases have the same input, but different expectations. Uncomment just one or the other.
|
52
|
+
|
53
|
+
/* Here you can test that you can reach the limit of the largest palindrome made of two 2-digit numbers.
|
54
|
+
{-99, -10, Product{}, Product{}, "Negative limits"}, */
|
55
|
+
|
56
|
+
// You can still get non-negative products from negative factors.
|
52
57
|
{-99, -10,
|
53
58
|
Product{121, [][2]int{{-11, -11}}},
|
54
59
|
Product{9009, [][2]int{{-99, -91}}},
|
55
60
|
""},
|
61
|
+
|
62
|
+
// The following two test cases have the same input, but different expectations. Uncomment just one or the other.
|
63
|
+
|
64
|
+
/*In case you reverse the *digits* you could have the following cases:
|
65
|
+
- the zero has to be considered
|
56
66
|
{-2, 2,
|
57
67
|
Product{0, [][2]int{{-2, 0}, {-1, 0}, {0, 0}, {0, 1}, {0, 2}}},
|
58
68
|
Product{4, [][2]int{{-2, -2}, {2, 2}}},
|
59
|
-
""},
|
60
|
-
|
69
|
+
""}, */
|
70
|
+
|
71
|
+
// - you can keep the minus sign in place
|
61
72
|
{-2, 2,
|
62
73
|
Product{-4, [][2]int{{-2, 2}}},
|
63
74
|
Product{4, [][2]int{{-2, -2}, {2, 2}}},
|
64
75
|
""},
|
65
|
-
{
|
66
|
-
{0, (^uint(0))>>1, Product{}, Product{}, "This one's gonna overflow"},
|
67
|
-
*/
|
68
76
|
}
|
69
77
|
|
70
78
|
func TestPalindromeProducts(t *testing.T) {
|
79
|
+
// Uncomment the following line to add the bonus test to the default tests
|
80
|
+
// testData = append(testData, bonusData...)
|
71
81
|
for _, test := range testData {
|
72
82
|
// common preamble for test failures
|
73
83
|
ret := fmt.Sprintf("Products(%d, %d) returned",
|
@@ -99,6 +109,12 @@ func TestPalindromeProducts(t *testing.T) {
|
|
99
109
|
}
|
100
110
|
}
|
101
111
|
|
112
|
+
func TestTestVersion(t *testing.T) {
|
113
|
+
if testVersion != targetTestVersion {
|
114
|
+
t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
102
118
|
func BenchmarkPalindromeProducts(b *testing.B) {
|
103
119
|
for i := 0; i < b.N; i++ {
|
104
120
|
for _, test := range testData {
|
data/tracks/haskell/.travis.yml
CHANGED
@@ -42,6 +42,13 @@ script:
|
|
42
42
|
SET_RESOLVER="--resolver ${RESOLVER}"
|
43
43
|
fi
|
44
44
|
|
45
|
+
test_exercise () {
|
46
|
+
stack test ${SET_RESOLVER} `# Select the correct resolver. `\
|
47
|
+
--install-ghc `# Download GHC if not in cache.`\
|
48
|
+
--no-terminal `# Terminal detection is broken.`\
|
49
|
+
--pedantic `# Enable -Wall and -Werror. `
|
50
|
+
}
|
51
|
+
|
45
52
|
for exercise in ${TRAVIS_BUILD_DIR}/exercises/* ; do
|
46
53
|
pushd ${exercise}
|
47
54
|
|
@@ -50,13 +57,25 @@ script:
|
|
50
57
|
mkdir -p "${HOME}/.foldercache/${exercise}/.stack-work"
|
51
58
|
ln -f -s "${HOME}/.foldercache/${exercise}/.stack-work"
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
if [ -f src/Example.hs ]; then
|
61
|
+
# Here we prepare the exercise to be tested by Stack.
|
62
|
+
MODULE=`sed -n 's/ *module \+\([a-zA-Z0-9]\+\).*/\1/p' src/Example.hs`
|
63
|
+
mv src/Example.hs "src/${MODULE}.hs"
|
64
|
+
|
65
|
+
test_exercise
|
66
|
+
elif ! stat -t examples/*/ > /dev/null 2>&1; then
|
67
|
+
echo "No examples for ${exercise}!"
|
68
|
+
exit 1
|
69
|
+
else
|
70
|
+
for example in examples/*/ ; do
|
71
|
+
echo "testing ${example}"
|
72
|
+
rm -f src/*.hs
|
73
|
+
mv ${example}/*.hs src
|
74
|
+
mv ${example}/package.yaml .
|
75
|
+
|
76
|
+
test_exercise
|
77
|
+
done
|
78
|
+
fi
|
56
79
|
|
57
|
-
stack test ${SET_RESOLVER} `# Select the correct resolver. `\
|
58
|
-
--install-ghc `# Download GHC if not in cache.`\
|
59
|
-
--no-terminal `# Terminal detection is broken.`\
|
60
|
-
--pedantic `# Enable -Wall and -Werror. `
|
61
80
|
popd
|
62
81
|
done
|
data/tracks/haskell/config.json
CHANGED
@@ -3,75 +3,6 @@
|
|
3
3
|
"language": "Haskell",
|
4
4
|
"repository": "https://github.com/exercism/xhaskell",
|
5
5
|
"active": true,
|
6
|
-
"problems": [
|
7
|
-
"leap",
|
8
|
-
"accumulate",
|
9
|
-
"sublist",
|
10
|
-
"grains",
|
11
|
-
"bob",
|
12
|
-
"sum-of-multiples",
|
13
|
-
"strain",
|
14
|
-
"hamming",
|
15
|
-
"rna-transcription",
|
16
|
-
"space-age",
|
17
|
-
"anagram",
|
18
|
-
"phone-number",
|
19
|
-
"nucleotide-count",
|
20
|
-
"grade-school",
|
21
|
-
"simple-linked-list",
|
22
|
-
"list-ops",
|
23
|
-
"word-count",
|
24
|
-
"etl",
|
25
|
-
"robot-name",
|
26
|
-
"meetup",
|
27
|
-
"beer-song",
|
28
|
-
"triangle",
|
29
|
-
"scrabble-score",
|
30
|
-
"roman-numerals",
|
31
|
-
"prime-factors",
|
32
|
-
"raindrops",
|
33
|
-
"allergies",
|
34
|
-
"atbash-cipher",
|
35
|
-
"all-your-base",
|
36
|
-
"bank-account",
|
37
|
-
"crypto-square",
|
38
|
-
"kindergarten-garden",
|
39
|
-
"robot-simulator",
|
40
|
-
"queen-attack",
|
41
|
-
"binary-search-tree",
|
42
|
-
"difference-of-squares",
|
43
|
-
"largest-series-product",
|
44
|
-
"luhn",
|
45
|
-
"clock",
|
46
|
-
"matrix",
|
47
|
-
"house",
|
48
|
-
"minesweeper",
|
49
|
-
"ocr-numbers",
|
50
|
-
"wordy",
|
51
|
-
"food-chain",
|
52
|
-
"linked-list",
|
53
|
-
"custom-set",
|
54
|
-
"nth-prime",
|
55
|
-
"palindrome-products",
|
56
|
-
"pascals-triangle",
|
57
|
-
"pig-latin",
|
58
|
-
"pythagorean-triplet",
|
59
|
-
"saddle-points",
|
60
|
-
"say",
|
61
|
-
"secret-handshake",
|
62
|
-
"series",
|
63
|
-
"sieve",
|
64
|
-
"simple-cipher",
|
65
|
-
"change",
|
66
|
-
"connect",
|
67
|
-
"parallel-letter-frequency",
|
68
|
-
"sgf-parsing",
|
69
|
-
"go-counting",
|
70
|
-
"zipper",
|
71
|
-
"forth",
|
72
|
-
"lens-person",
|
73
|
-
"pov"
|
74
|
-
],
|
75
6
|
"exercises": [
|
76
7
|
{
|
77
8
|
"slug": "leap",
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Anagram (anagramsFor) where
|
2
|
+
import Data.List (sort)
|
3
|
+
import Data.Char (toLower)
|
4
|
+
|
5
|
+
anagramsFor :: String -> [String] -> [String]
|
6
|
+
anagramsFor word = filter (isAnagram . normalize)
|
7
|
+
where
|
8
|
+
normalize xs = let nxs = map toLower xs in (nxs, sort nxs)
|
9
|
+
(nw, sw) = normalize word
|
10
|
+
isAnagram (w, s) = nw /= w && sw == s
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
name: anagram
|
2
|
+
|
3
|
+
dependencies:
|
4
|
+
- base
|
5
|
+
|
6
|
+
library:
|
7
|
+
exposed-modules: Anagram
|
8
|
+
source-dirs: src
|
9
|
+
dependencies:
|
10
|
+
- containers
|
11
|
+
- multiset
|
12
|
+
- text
|
13
|
+
|
14
|
+
tests:
|
15
|
+
test:
|
16
|
+
main: Tests.hs
|
17
|
+
source-dirs: test
|
18
|
+
dependencies:
|
19
|
+
- anagram
|
20
|
+
- hspec
|