Skip to content

Commit 843767c

Browse files
tommyschaeferkotp
authored andcommitted
WIP: all-your-base: add test generator (#510)
* Generate tests for "all your base" * Move private row attribute to avoid ruby warning This change is to remove a warning present in ruby versions less than 2.3.0. A thread discussing this warning can be found at https://bugs.ruby-lang.org/issues/10967. It is removed in ruby/ruby@32a5a09. * A bit more idiomatic Ruby Also, the private call was ineffective.
1 parent 768b694 commit 843767c

File tree

5 files changed

+190
-68
lines changed

5 files changed

+190
-68
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2

exercises/all-your-base/all_your_base_test.rb

Lines changed: 50 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
gem 'minitest', '>= 5.0.0'
21
require 'minitest/autorun'
32
require_relative 'all_your_base'
43

4+
# Test data version: aa12f2e
55
class AllYourBaseTest < Minitest::Test
6-
def test_single_bit_to_one_decimal
6+
def test_single_bit_one_to_decimal
7+
# skip
78
digits = [1]
89
input_base = 2
910
output_base = 10
@@ -131,7 +132,7 @@ def test_empty_list
131132
def test_single_zero
132133
skip
133134
digits = [0]
134-
input_base = 10
135+
input_base = 10
135136
output_base = 2
136137
expected = [0]
137138

@@ -142,10 +143,10 @@ def test_single_zero
142143
"Expected #{expected} but got #{converted}."
143144
end
144145

145-
def test_multiple_zeroes
146+
def test_multiple_zeros
146147
skip
147148
digits = [0, 0, 0]
148-
input_base = 10
149+
input_base = 10
149150
output_base = 2
150151
expected = [0]
151152

@@ -175,129 +176,118 @@ def test_negative_digit
175176
digits = [1, -1, 1, 0, 1, 0]
176177
input_base = 2
177178
output_base = 10
178-
expected = nil
179-
180-
converted = BaseConverter.convert(input_base, digits, output_base)
181179

182-
assert_equal expected, converted,
183-
"Input base: #{input_base}, output base #{output_base}. " \
184-
"Expected #{expected} but got #{converted}."
180+
assert_raises ArgumentError do
181+
BaseConverter.convert(input_base, digits, output_base)
182+
end
185183
end
186184

187185
def test_invalid_positive_digit
188186
skip
189187
digits = [1, 2, 1, 0, 1, 0]
190188
input_base = 2
191189
output_base = 10
192-
expected = nil
193-
194-
converted = BaseConverter.convert(input_base, digits, output_base)
195190

196-
assert_equal expected, converted,
197-
"Input base: #{input_base}, output base #{output_base}. " \
198-
"Expected #{expected} but got #{converted}."
191+
assert_raises ArgumentError do
192+
BaseConverter.convert(input_base, digits, output_base)
193+
end
199194
end
200195

201196
def test_first_base_is_one
202197
skip
203198
digits = []
204199
input_base = 1
205200
output_base = 10
206-
expected = nil
207201

208-
converted = BaseConverter.convert(input_base, digits, output_base)
209-
210-
assert_equal expected, converted,
211-
"Input base: #{input_base}, output base #{output_base}. " \
212-
"Expected #{expected} but got #{converted}."
202+
assert_raises ArgumentError do
203+
BaseConverter.convert(input_base, digits, output_base)
204+
end
213205
end
214206

215207
def test_second_base_is_one
216208
skip
217209
digits = [1, 0, 1, 0, 1, 0]
218210
input_base = 2
219211
output_base = 1
220-
expected = nil
221-
222-
converted = BaseConverter.convert(input_base, digits, output_base)
223212

224-
assert_equal expected, converted,
225-
"Input base: #{input_base}, output base #{output_base}. " \
226-
"Expected #{expected} but got #{converted}."
213+
assert_raises ArgumentError do
214+
BaseConverter.convert(input_base, digits, output_base)
215+
end
227216
end
228217

229218
def test_first_base_is_zero
230219
skip
231220
digits = []
232221
input_base = 0
233222
output_base = 10
234-
expected = nil
235-
236-
converted = BaseConverter.convert(input_base, digits, output_base)
237223

238-
assert_equal expected, converted,
239-
"Input base: #{input_base}, output base #{output_base}. " \
240-
"Expected #{expected} but got #{converted}."
224+
assert_raises ArgumentError do
225+
BaseConverter.convert(input_base, digits, output_base)
226+
end
241227
end
242228

243229
def test_second_base_is_zero
244230
skip
245231
digits = [7]
246232
input_base = 10
247233
output_base = 0
248-
expected = nil
249234

250-
converted = BaseConverter.convert(input_base, digits, output_base)
251-
252-
assert_equal expected, converted,
253-
"Input base: #{input_base}, output base #{output_base}. " \
254-
"Expected #{expected} but got #{converted}."
235+
assert_raises ArgumentError do
236+
BaseConverter.convert(input_base, digits, output_base)
237+
end
255238
end
256239

257240
def test_first_base_is_negative
258241
skip
259242
digits = [1]
260243
input_base = -2
261244
output_base = 10
262-
expected = nil
263-
264-
converted = BaseConverter.convert(input_base, digits, output_base)
265245

266-
assert_equal expected, converted,
267-
"Input base: #{input_base}, output base #{output_base}. " \
268-
"Expected #{expected} but got #{converted}."
246+
assert_raises ArgumentError do
247+
BaseConverter.convert(input_base, digits, output_base)
248+
end
269249
end
270250

271251
def test_second_base_is_negative
272252
skip
273253
digits = [1]
274254
input_base = 2
275255
output_base = -7
276-
expected = nil
277-
278-
converted = BaseConverter.convert(input_base, digits, output_base)
279256

280-
assert_equal expected, converted,
281-
"Input base: #{input_base}, output base #{output_base}. " \
282-
"Expected #{expected} but got #{converted}."
257+
assert_raises ArgumentError do
258+
BaseConverter.convert(input_base, digits, output_base)
259+
end
283260
end
284261

285262
def test_both_bases_are_negative
286263
skip
287264
digits = [1]
288265
input_base = -2
289266
output_base = -7
290-
expected = nil
291267

292-
converted = BaseConverter.convert(input_base, digits, output_base)
293-
294-
assert_equal expected, converted,
295-
"Input base: #{input_base}, output base #{output_base}. " \
296-
"Expected #{expected} but got #{converted}."
268+
assert_raises ArgumentError do
269+
BaseConverter.convert(input_base, digits, output_base)
270+
end
297271
end
298272

273+
# Problems in exercism evolve over time, as we find better ways to ask
274+
# questions.
275+
# The version number refers to the version of the problem you solved,
276+
# not your solution.
277+
#
278+
# Define a constant named VERSION inside of the top level BookKeeping
279+
# module, which may be placed near the end of your file.
280+
#
281+
# In your file, it will look like this:
282+
#
283+
# module BookKeeping
284+
# VERSION = 1 # Where the version number matches the one in the test.
285+
# end
286+
#
287+
# If you are curious, read more about constants on RubyDoc:
288+
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html
299289
def test_bookkeeping
300290
skip
301-
assert_equal 1, BookKeeping::VERSION
291+
assert_equal 2, BookKeeping::VERSION
302292
end
303293
end

exercises/all-your-base/example.rb

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
module BookKeeping
2-
VERSION = 1
2+
VERSION = 2
33
end
44

55
class BaseConverter
66
def self.convert(base_from, number_array, base_to)
7-
return if number_array.any?{|number| number < 0 || number >= base_from}
8-
return if base_from <= 1 || base_to <= 1
7+
fail ArgumentError if invalid_inputs?(base_from, number_array, base_to)
98
return [] unless number_array.any?
109
number_in_canonical_base = convert_to_canonical_base(number_array, base_from)
1110
convert_from_canonical_base(number_in_canonical_base, base_to)
1211
end
1312

14-
private
13+
private_class_method
14+
15+
def self.invalid_inputs?(base_from, number_array, base_to)
16+
number_array.any? { |number| number < 0 || number >= base_from } ||
17+
base_from <= 1 || base_to <= 1
18+
end
19+
1520
def self.convert_to_canonical_base(number_array, base)
1621
total = 0
1722
number_array.reverse.each_with_index do |number, index|
18-
total += number * base ** index
23+
total += number * base**index
1924
end
2025
total
2126
end
2227

2328
def self.convert_from_canonical_base(number, base_to)
2429
result = []
2530
current_number = number
26-
while current_number >= base_to do
27-
result << current_number % base_to
28-
current_number = current_number / base_to
31+
while current_number >= base_to
32+
result << current_number % base_to
33+
current_number /= base_to
2934
end
3035
result << current_number % base_to
3136
result.reverse

exercises/all-your-base/example.tt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'minitest/autorun'
2+
require_relative 'all_your_base'
3+
4+
# Test data version: <%= sha1 %>
5+
class AllYourBaseTest < Minitest::Test<% test_cases.each do |test_case| %>
6+
def <%= test_case.test_name %>
7+
<%= test_case.skipped %>
8+
<%= test_case.workload %>
9+
end
10+
<% end %>
11+
12+
<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %>
13+
def test_bookkeeping
14+
skip
15+
assert_equal <%= version.next %>, BookKeeping::VERSION
16+
end
17+
end

lib/all_your_base_cases.rb

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
class AllYourBaseCase < OpenStruct
2+
def test_name
3+
'test_%s' % description.downcase.tr(' -', '_')
4+
end
5+
6+
def workload
7+
indent(4, (assignments + assertion).join("\n")) + "\n"
8+
end
9+
10+
def skipped
11+
index.zero? ? '# skip' : 'skip'
12+
end
13+
14+
private
15+
16+
def indent(size, text)
17+
text.lines.each_with_object('') do |line, obj|
18+
obj << (line == "\n" ? line : ' ' * size + line)
19+
end
20+
end
21+
22+
def assignments
23+
[
24+
"digits = #{input_digits}",
25+
"input_base = #{input_base}",
26+
"output_base = #{output_base}",
27+
]
28+
end
29+
30+
def assertion
31+
return error_assertion unless expected
32+
33+
[
34+
"expected = #{expected}",
35+
"",
36+
"converted = BaseConverter.convert(input_base, digits, output_base)",
37+
"",
38+
"assert_equal expected, converted,",
39+
indent(13, error_message),
40+
]
41+
end
42+
43+
def error_assertion
44+
[
45+
"",
46+
"assert_raises ArgumentError do",
47+
" BaseConverter.convert(input_base, digits, output_base)",
48+
"end",
49+
]
50+
end
51+
52+
def error_message
53+
%q("Input base: #{input_base}, output base #{output_base}. " \\) \
54+
"\n" + %q("Expected #{expected} but got #{converted}.")
55+
end
56+
end
57+
58+
class AllYourBaseCase::PreProcessor
59+
class << self
60+
attr_reader :row
61+
62+
def call(row)
63+
@row = row
64+
65+
row.merge('expected' => expected_value)
66+
end
67+
68+
private :row
69+
private
70+
71+
def expected_value
72+
return row['expected'] if row['expected']
73+
74+
if invalid_input_digits? || invalid_bases?
75+
nil
76+
elsif row['input_digits'].empty?
77+
[]
78+
elsif input_of_zero?
79+
[0]
80+
else
81+
handle_special_cases
82+
end
83+
end
84+
85+
def invalid_input_digits?
86+
row['input_digits'].any? { |x| x < 0 || x >= row['input_base'] }
87+
end
88+
89+
def invalid_bases?
90+
row['input_base'] <= 1 || row['output_base'] <= 1
91+
end
92+
93+
def input_of_zero?
94+
row['input_digits'].all? { |x| x == 0 }
95+
end
96+
97+
def handle_special_cases
98+
[4,2] if row['input_digits'] == [0, 6, 0]
99+
end
100+
end
101+
end
102+
103+
AllYourBaseCases = proc do |data|
104+
JSON.parse(data)['cases'].map.with_index do |row, i|
105+
AllYourBaseCase.new(
106+
AllYourBaseCase::PreProcessor.call(row).merge(index: i),
107+
)
108+
end
109+
end

0 commit comments

Comments
 (0)