diff --git a/exercises/grains/.meta/.version b/exercises/grains/.meta/.version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/exercises/grains/.meta/.version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/exercises/grains/example.rb b/exercises/grains/example.rb index 5afad3b8db..0ebb75cc42 100644 --- a/exercises/grains/example.rb +++ b/exercises/grains/example.rb @@ -1,9 +1,14 @@ +module BookKeeping + VERSION = 1 +end + module Grains def self.square(number) + fail ArgumentError if number <= 0 || number > 64 2**(number - 1) end def self.total - square(65) - 1 + 2**64 - 1 end end diff --git a/exercises/grains/example.tt b/exercises/grains/example.tt new file mode 100644 index 0000000000..6aa03653e2 --- /dev/null +++ b/exercises/grains/example.tt @@ -0,0 +1,17 @@ +require 'minitest/autorun' +require_relative 'grains' + +# Test data version: <%= sha1 %> +class GrainsTest < Minitest::Test<% test_cases.each do |test_case| %> + def <%= test_case.test_name %> + <%= test_case.skipped %> + <%= test_case.workload %> + end +<% end %> + +<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping + skip + assert_equal <%= version.next %>, BookKeeping::VERSION + end +end diff --git a/exercises/grains/grains_test.rb b/exercises/grains/grains_test.rb index 9f4dcc7933..db99758d62 100755 --- a/exercises/grains/grains_test.rb +++ b/exercises/grains/grains_test.rb @@ -1,45 +1,81 @@ -#!/usr/bin/env ruby -gem 'minitest', '>= 5.0.0' require 'minitest/autorun' require_relative 'grains' +# Test data version: aa12f2e class GrainsTest < Minitest::Test - def test_square_1 + def test_1 + # skip assert_equal 1, Grains.square(1) end - def test_square_2 + def test_2 skip assert_equal 2, Grains.square(2) end - def test_square_3 + def test_3 skip assert_equal 4, Grains.square(3) end - def test_square_4 + def test_4 skip assert_equal 8, Grains.square(4) end - def test_square_16 + def test_16 skip assert_equal 32_768, Grains.square(16) end - def test_square_32 + def test_32 skip assert_equal 2_147_483_648, Grains.square(32) end - def test_square_64 + def test_64 skip assert_equal 9_223_372_036_854_775_808, Grains.square(64) end - def test_total_grains + def test_square_0_raises_an_exception + skip + assert_raises(ArgumentError) { Grains.square(0) } + end + + def test_negative_square_raises_an_exception + skip + assert_raises(ArgumentError) { Grains.square(-1) } + end + + def test_square_greater_than_64_raises_an_exception + skip + assert_raises(ArgumentError) { Grains.square(65) } + end + + def test_returns_the_total_number_of_grains_on_the_board skip assert_equal 18_446_744_073_709_551_615, Grains.total end + + # Problems in exercism evolve over time, as we find better ways to ask + # questions. + # The version number refers to the version of the problem you solved, + # not your solution. + # + # Define a constant named VERSION inside of the top level BookKeeping + # module, which may be placed near the end of your file. + # + # In your file, it will look like this: + # + # module BookKeeping + # VERSION = 1 # Where the version number matches the one in the test. + # end + # + # If you are curious, read more about constants on RubyDoc: + # http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html + def test_bookkeeping + skip + assert_equal 1, BookKeeping::VERSION + end end diff --git a/lib/grains_cases.rb b/lib/grains_cases.rb new file mode 100644 index 0000000000..e7419bbb72 --- /dev/null +++ b/lib/grains_cases.rb @@ -0,0 +1,51 @@ +class GrainsCase < OpenStruct + def test_name + 'test_%s' % description.downcase.tr_s(' ', '_') + end + + def workload + fail NotImplementedError + end + + def skipped + index.zero? ? '# skip' : 'skip' + end + + private + + def underscore_format(number) + number.to_s.reverse.gsub(/...(?=.)/,'\&_').reverse + end +end + +class GrainsCase::SquareMethod < GrainsCase + def workload + return error_assertion if expected < 0 + + "assert_equal #{underscore_format(expected)}, Grains.square(#{input})" + end + + private + + def error_assertion + "assert_raises(ArgumentError) { Grains.square(#{input}) }" + end +end + +class GrainsCase::TotalMethod < GrainsCase + def workload + "assert_equal #{underscore_format(expected)}, Grains.total" + end +end + +GrainsCases = proc do |data| + data = JSON.parse(data) + + cases = data['square']['cases'].map.with_index do |row, i| + GrainsCase::SquareMethod.new(row.merge('index' => i)) + end + + cases << GrainsCase::TotalMethod.new( + data['total'].merge('index' => cases.size) + ) +end diff --git a/test/grains_cases_test.rb b/test/grains_cases_test.rb new file mode 100644 index 0000000000..cee8b7fdc7 --- /dev/null +++ b/test/grains_cases_test.rb @@ -0,0 +1,102 @@ +require_relative 'test_helper' + +class GrainsTest < Minitest::Test + def test_test_name + test_case = GrainsCase.new(description: 'description') + + assert_equal 'test_description', test_case.test_name + end + + def test_test_name_when_description_has_spaces + test_case = GrainsCase.new(description: 'description with spaces') + + assert_equal 'test_description_with_spaces', test_case.test_name + end + + def test_workload_is_not_implemented + assert_raises(NotImplementedError) { GrainsCase.new.workload } + end + + def test_skipped_with_zero_index + assert_equal '# skip', GrainsCase.new(index: 0).skipped + end + + def test_skipped_with_non_zero_index + assert_equal 'skip', GrainsCase.new(index: 1).skipped + end +end + +class SquareMethodTest < Minitest::Test + def test_workload_when_expected_is_negative + test_case = GrainsCase::SquareMethod.new(expected: -1, input: 10) + + assert_equal 'assert_raises(ArgumentError) { Grains.square(10) }', + test_case.workload + end + + def test_workload_when_expected_is_positive + test_case = GrainsCase::SquareMethod.new(expected: 1, input: 10) + + assert_equal 'assert_equal 1, Grains.square(10)', test_case.workload + end + + def test_workload_with_large_expected_number + test_case = GrainsCase::SquareMethod.new(expected: 10000, input: 10) + + assert_equal 'assert_equal 10_000, Grains.square(10)', test_case.workload + end +end + +class TotalMethodTest < Minitest::Test + def test_workload + test_case = GrainsCase::TotalMethod.new(expected: 1) + + assert_equal 'assert_equal 1, Grains.total', test_case.workload + end + + def test_workload_with_large_expected_number + test_case = GrainsCase::TotalMethod.new(expected: 10000) + + assert_equal 'assert_equal 10_000, Grains.total', test_case.workload + end +end + +class GrainsCasesTest < Minitest::Test + def test_handling_of_json + json = { + square: { + cases: [ + {}, + {}, + ], + }, + total: { + } + }.to_json + + cases = GrainsCases.call(json) + + assert_instance_of GrainsCase::SquareMethod, cases[0] + assert_instance_of GrainsCase::SquareMethod, cases[1] + assert_instance_of GrainsCase::TotalMethod, cases[2] + end + + def test_continuous_index + json = { + square: { + cases: [ + {}, + {}, + ], + }, + total: { + } + }.to_json + + cases = GrainsCases.call(json) + + assert_equal 0, cases[0].index + assert_equal 1, cases[1].index + assert_equal 2, cases[2].index + end +end